aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-regulator55
-rw-r--r--Documentation/ABI/testing/sysfs-profiling13
-rw-r--r--Documentation/DocBook/procfs-guide.tmpl29
-rw-r--r--Documentation/DocBook/procfs_example.c20
-rw-r--r--Documentation/HOWTO4
-rw-r--r--Documentation/SAK.txt2
-rw-r--r--Documentation/SubmitChecklist3
-rw-r--r--Documentation/SubmittingDrivers2
-rw-r--r--Documentation/SubmittingPatches9
-rw-r--r--Documentation/cris/README2
-rw-r--r--Documentation/dontdiff59
-rw-r--r--Documentation/fb/intelfb.txt1
-rw-r--r--Documentation/fb/uvesafb.txt4
-rw-r--r--Documentation/fb/viafb.modes870
-rw-r--r--Documentation/fb/viafb.txt214
-rw-r--r--Documentation/feature-removal-schedule.txt16
-rw-r--r--Documentation/filesystems/autofs4-mount-control.txt393
-rw-r--r--Documentation/filesystems/ext3.txt3
-rw-r--r--Documentation/filesystems/nfsroot.txt2
-rw-r--r--Documentation/filesystems/ocfs2.txt6
-rw-r--r--Documentation/filesystems/proc.txt12
-rw-r--r--Documentation/filesystems/ramfs-rootfs-initramfs.txt2
-rw-r--r--Documentation/gpio.txt9
-rw-r--r--Documentation/i2c/busses/i2c-viapro8
-rw-r--r--Documentation/i2c/dev-interface110
-rw-r--r--Documentation/i2c/smbus-protocol4
-rw-r--r--Documentation/i2c/writing-clients4
-rw-r--r--Documentation/ia64/kvm.txt9
-rw-r--r--Documentation/networking/cs89x0.txt4
-rw-r--r--Documentation/networking/vortex.txt9
-rw-r--r--Documentation/power/regulator/machine.txt140
-rw-r--r--Documentation/power/regulator/regulator.txt8
-rw-r--r--Documentation/power/s2ram.txt18
-rw-r--r--Documentation/powerpc/00-INDEX4
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt40
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt40
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/dma.txt13
-rw-r--r--Documentation/powerpc/dts-bindings/fsl/ssi.txt23
-rw-r--r--Documentation/powerpc/ppc_htab.txt118
-rw-r--r--Documentation/powerpc/smp.txt34
-rw-r--r--Documentation/scsi/ChangeLog.megaraid6
-rw-r--r--Documentation/spi/pxa2xx34
-rw-r--r--Documentation/w1/00-INDEX2
-rw-r--r--Documentation/w1/masters/ds249052
-rw-r--r--Documentation/w1/slaves/00-INDEX4
-rw-r--r--Documentation/w1/slaves/w1_therm41
-rw-r--r--Documentation/w1/w1.generic11
-rw-r--r--MAINTAINERS25
-rw-r--r--arch/Kconfig18
-rw-r--r--arch/alpha/Kconfig3
-rw-r--r--arch/alpha/include/asm/a.out.h2
-rw-r--r--arch/alpha/kernel/pci_iommu.c17
-rw-r--r--arch/alpha/kernel/smp.c1
-rw-r--r--arch/arm/mach-integrator/cpu.c1
-rw-r--r--arch/arm/mach-omap1/board-h3.c4
-rw-r--r--arch/arm/mach-omap2/board-h4.c11
-rw-r--r--arch/arm/mach-pxa/cpufreq-pxa2xx.c3
-rw-r--r--arch/arm/mach-pxa/cpufreq-pxa3xx.c1
-rw-r--r--arch/arm/mach-s3c2410/include/mach/spi.h1
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1100.c1
-rw-r--r--arch/avr32/mach-at32ap/cpufreq.c1
-rw-r--r--arch/blackfin/mach-common/cpufreq.c2
-rw-r--r--arch/cris/arch-v32/mach-a3/cpufreq.c1
-rw-r--r--arch/cris/arch-v32/mach-fs/cpufreq.c1
-rw-r--r--arch/frv/kernel/pm.c6
-rw-r--r--arch/h8300/Kconfig4
-rw-r--r--arch/h8300/Kconfig.cpu115
-rw-r--r--arch/h8300/include/asm/bug.h4
-rw-r--r--arch/h8300/include/asm/io.h34
-rw-r--r--arch/h8300/include/asm/md.h2
-rw-r--r--arch/h8300/include/asm/system.h2
-rw-r--r--arch/h8300/kernel/Makefile2
-rw-r--r--arch/h8300/kernel/module.c3
-rw-r--r--arch/h8300/kernel/time.c29
-rw-r--r--arch/h8300/kernel/timer/Makefile6
-rw-r--r--arch/h8300/kernel/timer/itu.c83
-rw-r--r--arch/h8300/kernel/timer/timer16.c78
-rw-r--r--arch/h8300/kernel/timer/timer8.c103
-rw-r--r--arch/h8300/kernel/timer/tpu.c102
-rw-r--r--arch/h8300/kernel/traps.c17
-rw-r--r--arch/h8300/mm/fault.c5
-rw-r--r--arch/h8300/platform/h8300h/aki3068net/Makefile1
-rw-r--r--arch/h8300/platform/h8300h/aki3068net/timer.c51
-rw-r--r--arch/h8300/platform/h8300h/generic/Makefile1
-rw-r--r--arch/h8300/platform/h8300h/generic/timer.c95
-rw-r--r--arch/h8300/platform/h8300h/h8max/Makefile1
-rw-r--r--arch/h8300/platform/h8300h/h8max/timer.c52
-rw-r--r--arch/h8300/platform/h8s/edosk2674/Makefile1
-rw-r--r--arch/h8300/platform/h8s/edosk2674/timer.c54
-rw-r--r--arch/h8300/platform/h8s/generic/Makefile1
-rw-r--r--arch/h8300/platform/h8s/generic/timer.c53
-rw-r--r--arch/ia64/Kconfig8
-rw-r--r--arch/ia64/ia32/ia32_entry.S4
-rw-r--r--arch/ia64/ia32/sys_ia32.c91
-rw-r--r--arch/m32r/kernel/process.c2
-rw-r--r--arch/m68k/Kconfig60
-rw-r--r--arch/m68k/amiga/config.c9
-rw-r--r--arch/m68k/atari/Makefile3
-rw-r--r--arch/m68k/atari/ataints.c6
-rw-r--r--arch/m68k/atari/atakeyb.c12
-rw-r--r--arch/m68k/atari/config.c37
-rw-r--r--arch/m68k/atari/hades-pci.c440
-rw-r--r--arch/m68k/atari/time.c38
-rw-r--r--arch/m68k/bvme6000/config.c15
-rw-r--r--arch/m68k/bvme6000/rtc.c30
-rw-r--r--arch/m68k/kernel/Makefile1
-rw-r--r--arch/m68k/kernel/bios32.c514
-rw-r--r--arch/m68k/kernel/dma.c4
-rw-r--r--arch/m68k/kernel/ints.c3
-rw-r--r--arch/m68k/kernel/process.c2
-rw-r--r--arch/m68k/kernel/traps.c9
-rw-r--r--arch/m68k/kernel/vmlinux-std.lds9
-rw-r--r--arch/m68k/mm/kmap.c4
-rw-r--r--arch/m68k/mvme16x/rtc.c26
-rw-r--r--arch/m68k/q40/config.c12
-rw-r--r--arch/m68k/sun3x/time.c28
-rw-r--r--arch/mips/Kconfig1
-rw-r--r--arch/mips/bcm47xx/gpio.c85
-rw-r--r--arch/mips/bcm47xx/setup.c5
-rw-r--r--arch/mips/bcm47xx/wgt634u.c40
-rw-r--r--arch/mips/emma2rh/common/irq.c1
-rw-r--r--arch/mips/emma2rh/common/prom.c1
-rw-r--r--arch/mips/emma2rh/markeins/platform.c1
-rw-r--r--arch/mips/include/asm/cevt-r4k.h (renamed from include/asm-mips/cevt-r4k.h)0
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/gpio.h41
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/war.h6
-rw-r--r--arch/mips/include/asm/mach-ip22/ds1286.h18
-rw-r--r--arch/mips/include/asm/mach-ip28/ds1286.h4
-rw-r--r--arch/mips/include/asm/spinlock.h2
-rw-r--r--arch/mips/kernel/linux32.c101
-rw-r--r--arch/mips/kernel/proc.c2
-rw-r--r--arch/mips/kernel/scall64-n32.S4
-rw-r--r--arch/mips/kernel/scall64-o32.S4
-rw-r--r--arch/mips/kernel/vmlinux.lds.S2
-rw-r--r--arch/mips/lasat/sysctl.c17
-rw-r--r--arch/mips/pci/fixup-emma2rh.c1
-rw-r--r--arch/mips/pci/ops-pnx8550.c2
-rw-r--r--arch/mips/pci/pci-emma2rh.c1
-rw-r--r--arch/mips/pci/pci.c80
-rw-r--r--arch/mips/rb532/time.c1
-rw-r--r--arch/mips/sgi-ip22/ip22-platform.c15
-rw-r--r--arch/mips/sgi-ip22/ip22-setup.c1
-rw-r--r--arch/mips/sgi-ip22/ip22-time.c64
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c99
-rw-r--r--arch/mips/sgi-ip32/ip32-platform.c16
-rw-r--r--arch/mips/sgi-ip32/ip32-setup.c5
-rw-r--r--arch/parisc/kernel/sys_parisc32.c105
-rw-r--r--arch/parisc/kernel/syscall_table.S4
-rw-r--r--arch/powerpc/Kconfig16
-rw-r--r--arch/powerpc/Kconfig.debug5
-rw-r--r--arch/powerpc/Makefile7
-rw-r--r--arch/powerpc/boot/Makefile3
-rw-r--r--arch/powerpc/boot/addnote.c144
-rw-r--r--arch/powerpc/boot/dtc-src/Makefile.dtc18
-rw-r--r--arch/powerpc/boot/dtc-src/checks.c305
-rw-r--r--arch/powerpc/boot/dtc-src/data.c62
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-lexer.l120
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped445
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped387
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped12
-rw-r--r--arch/powerpc/boot/dtc-src/dtc-parser.y67
-rw-r--r--arch/powerpc/boot/dtc-src/dtc.c41
-rw-r--r--arch/powerpc/boot/dtc-src/dtc.h43
-rw-r--r--arch/powerpc/boot/dtc-src/flattree.c232
-rw-r--r--arch/powerpc/boot/dtc-src/fstree.c8
-rw-r--r--arch/powerpc/boot/dtc-src/libfdt_env.h23
-rw-r--r--arch/powerpc/boot/dtc-src/livetree.c9
-rw-r--r--arch/powerpc/boot/dtc-src/srcpos.c121
-rw-r--r--arch/powerpc/boot/dtc-src/srcpos.h30
-rw-r--r--arch/powerpc/boot/dtc-src/treesource.c15
-rw-r--r--arch/powerpc/boot/dtc-src/version_gen.h2
-rw-r--r--arch/powerpc/boot/dts/arches.dts293
-rw-r--r--arch/powerpc/boot/dts/asp834x-redboot.dts4
-rw-r--r--arch/powerpc/boot/dts/gef_sbc610.dts293
-rw-r--r--arch/powerpc/boot/dts/glacier.dts2
-rw-r--r--arch/powerpc/boot/dts/mgcoge.dts174
-rw-r--r--arch/powerpc/boot/dts/mgsuvd.dts163
-rw-r--r--arch/powerpc/boot/dts/mpc5121ads.dts3
-rw-r--r--arch/powerpc/boot/dts/mpc8313erdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8315erdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc832x_mds.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc832x_rdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitxgp.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc834x_mds.dts10
-rw-r--r--arch/powerpc/boot/dts/mpc836x_mds.dts30
-rw-r--r--arch/powerpc/boot/dts/mpc836x_rdk.dts19
-rw-r--r--arch/powerpc/boot/dts/mpc8377_mds.dts14
-rw-r--r--arch/powerpc/boot/dts/mpc8377_rdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8378_mds.dts14
-rw-r--r--arch/powerpc/boot/dts/mpc8378_rdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8379_mds.dts14
-rw-r--r--arch/powerpc/boot/dts/mpc8379_rdb.dts7
-rw-r--r--arch/powerpc/boot/dts/mpc8536ds.dts2
-rw-r--r--arch/powerpc/boot/dts/mpc8610_hpcd.dts12
-rw-r--r--arch/powerpc/boot/dts/sbc8349.dts7
-rw-r--r--arch/powerpc/boot/dts/sequoia.dts9
-rw-r--r--arch/powerpc/boot/dts/yosemite.dts2
-rw-r--r--arch/powerpc/boot/elf_util.c6
-rw-r--r--arch/powerpc/boot/libfdt/Makefile.libfdt8
-rw-r--r--arch/powerpc/boot/libfdt/fdt.c61
-rw-r--r--arch/powerpc/boot/libfdt/fdt_ro.c329
-rw-r--r--arch/powerpc/boot/libfdt/fdt_rw.c200
-rw-r--r--arch/powerpc/boot/libfdt/fdt_strerror.c34
-rw-r--r--arch/powerpc/boot/libfdt/fdt_sw.c55
-rw-r--r--arch/powerpc/boot/libfdt/fdt_wip.c9
-rw-r--r--arch/powerpc/boot/libfdt/libfdt.h383
-rw-r--r--arch/powerpc/boot/libfdt/libfdt_internal.h24
-rw-r--r--arch/powerpc/boot/libfdt_env.h1
-rwxr-xr-xarch/powerpc/boot/wrapper4
-rw-r--r--arch/powerpc/configs/44x/arches_defconfig767
-rw-r--r--arch/powerpc/configs/83xx/asp8347_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc8313_rdb_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc8315_rdb_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_mds_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc832x_rdb_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itx_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc834x_mds_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_mds_defconfig83
-rw-r--r--arch/powerpc/configs/83xx/mpc836x_rdk_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_mds_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/mpc837x_rdb_defconfig4
-rw-r--r--arch/powerpc/configs/83xx/sbc834x_defconfig4
-rw-r--r--arch/powerpc/configs/86xx/gef_sbc610_defconfig1657
-rw-r--r--arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig (renamed from arch/powerpc/configs/mpc8610_hpcd_defconfig)4
-rw-r--r--arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig (renamed from arch/powerpc/configs/mpc8641_hpcn_defconfig)4
-rw-r--r--arch/powerpc/configs/86xx/sbc8641d_defconfig (renamed from arch/powerpc/configs/sbc8641d_defconfig)4
-rw-r--r--arch/powerpc/configs/ep8248e_defconfig4
-rw-r--r--arch/powerpc/configs/mgcoge_defconfig900
-rw-r--r--arch/powerpc/configs/mgsuvd_defconfig872
-rw-r--r--arch/powerpc/configs/mpc8272_ads_defconfig4
-rw-r--r--arch/powerpc/configs/mpc83xx_defconfig4
-rw-r--r--arch/powerpc/configs/mpc86xx_defconfig1646
-rw-r--r--arch/powerpc/configs/pq2fads_defconfig4
-rw-r--r--arch/powerpc/include/asm/cputable.h10
-rw-r--r--arch/powerpc/include/asm/dcr-regs.h7
-rw-r--r--arch/powerpc/include/asm/device.h3
-rw-r--r--arch/powerpc/include/asm/dma-mapping.h187
-rw-r--r--arch/powerpc/include/asm/exception.h42
-rw-r--r--arch/powerpc/include/asm/fsl_lbc.h48
-rw-r--r--arch/powerpc/include/asm/highmem.h2
-rw-r--r--arch/powerpc/include/asm/io.h2
-rw-r--r--arch/powerpc/include/asm/irq.h18
-rw-r--r--arch/powerpc/include/asm/machdep.h5
-rw-r--r--arch/powerpc/include/asm/mman.h2
-rw-r--r--arch/powerpc/include/asm/mmu-hash64.h2
-rw-r--r--arch/powerpc/include/asm/mpic.h4
-rw-r--r--arch/powerpc/include/asm/msi_bitmap.h35
-rw-r--r--arch/powerpc/include/asm/of_device.h3
-rw-r--r--arch/powerpc/include/asm/of_platform.h3
-rw-r--r--arch/powerpc/include/asm/paca.h2
-rw-r--r--arch/powerpc/include/asm/page.h14
-rw-r--r--arch/powerpc/include/asm/page_32.h8
-rw-r--r--arch/powerpc/include/asm/pci.h14
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc32.h72
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h12
-rw-r--r--arch/powerpc/include/asm/ppc_asm.h2
-rw-r--r--arch/powerpc/include/asm/reg_booke.h7
-rw-r--r--arch/powerpc/include/asm/sections.h6
-rw-r--r--arch/powerpc/include/asm/sfp-machine.h (renamed from arch/powerpc/math-emu/sfp-machine.h)114
-rw-r--r--arch/powerpc/include/asm/smp.h42
-rw-r--r--arch/powerpc/include/asm/systbl.h2
-rw-r--r--arch/powerpc/include/asm/tlbflush.h13
-rw-r--r--arch/powerpc/include/asm/types.h2
-rw-r--r--arch/powerpc/kernel/.gitignore1
-rw-r--r--arch/powerpc/kernel/Makefile9
-rw-r--r--arch/powerpc/kernel/asm-offsets.c3
-rw-r--r--arch/powerpc/kernel/btext.c34
-rw-r--r--arch/powerpc/kernel/cpu_setup_ppc970.S4
-rw-r--r--arch/powerpc/kernel/cputable.c24
-rw-r--r--arch/powerpc/kernel/dma-iommu.c (renamed from arch/powerpc/kernel/dma_64.c)101
-rw-r--r--arch/powerpc/kernel/dma.c131
-rw-r--r--arch/powerpc/kernel/entry_64.S69
-rw-r--r--arch/powerpc/kernel/head_32.S10
-rw-r--r--arch/powerpc/kernel/head_64.S473
-rw-r--r--arch/powerpc/kernel/head_fsl_booke.S26
-rw-r--r--arch/powerpc/kernel/iommu.c23
-rw-r--r--arch/powerpc/kernel/irq.c169
-rw-r--r--arch/powerpc/kernel/lparcfg.c8
-rw-r--r--arch/powerpc/kernel/misc.S10
-rw-r--r--arch/powerpc/kernel/misc_32.S62
-rw-r--r--arch/powerpc/kernel/misc_64.S8
-rw-r--r--arch/powerpc/kernel/of_device.c2
-rw-r--r--arch/powerpc/kernel/paca.c3
-rw-r--r--arch/powerpc/kernel/pci-common.c216
-rw-r--r--arch/powerpc/kernel/pci_32.c18
-rw-r--r--arch/powerpc/kernel/pci_64.c49
-rw-r--r--arch/powerpc/kernel/ppc_ksyms.c3
-rw-r--r--arch/powerpc/kernel/prom.c43
-rw-r--r--arch/powerpc/kernel/prom_init.c29
-rw-r--r--arch/powerpc/kernel/reloc_64.S87
-rw-r--r--arch/powerpc/kernel/setup-common.c17
-rw-r--r--arch/powerpc/kernel/setup_32.c13
-rw-r--r--arch/powerpc/kernel/setup_64.c9
-rw-r--r--arch/powerpc/kernel/smp.c3
-rw-r--r--arch/powerpc/kernel/swsusp_asm64.S2
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c107
-rw-r--r--arch/powerpc/kernel/sysfs.c119
-rw-r--r--arch/powerpc/kernel/vio.c2
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S18
-rw-r--r--arch/powerpc/lib/copypage_64.S198
-rw-r--r--arch/powerpc/lib/dma-noncoherent.c2
-rw-r--r--arch/powerpc/math-emu/Makefile7
-rw-r--r--arch/powerpc/math-emu/double.h129
-rw-r--r--arch/powerpc/math-emu/fadd.c17
-rw-r--r--arch/powerpc/math-emu/fadds.c20
-rw-r--r--arch/powerpc/math-emu/fcmpo.c10
-rw-r--r--arch/powerpc/math-emu/fcmpu.c10
-rw-r--r--arch/powerpc/math-emu/fctiw.c8
-rw-r--r--arch/powerpc/math-emu/fctiwz.c8
-rw-r--r--arch/powerpc/math-emu/fdiv.c14
-rw-r--r--arch/powerpc/math-emu/fdivs.c16
-rw-r--r--arch/powerpc/math-emu/fmadd.c16
-rw-r--r--arch/powerpc/math-emu/fmadds.c18
-rw-r--r--arch/powerpc/math-emu/fmsub.c16
-rw-r--r--arch/powerpc/math-emu/fmsubs.c18
-rw-r--r--arch/powerpc/math-emu/fmul.c14
-rw-r--r--arch/powerpc/math-emu/fmuls.c16
-rw-r--r--arch/powerpc/math-emu/fnmadd.c16
-rw-r--r--arch/powerpc/math-emu/fnmadds.c18
-rw-r--r--arch/powerpc/math-emu/fnmsub.c16
-rw-r--r--arch/powerpc/math-emu/fnmsubs.c18
-rw-r--r--arch/powerpc/math-emu/frsp.c14
-rw-r--r--arch/powerpc/math-emu/fsel.c8
-rw-r--r--arch/powerpc/math-emu/fsqrt.c12
-rw-r--r--arch/powerpc/math-emu/fsqrts.c14
-rw-r--r--arch/powerpc/math-emu/fsub.c14
-rw-r--r--arch/powerpc/math-emu/fsubs.c16
-rw-r--r--arch/powerpc/math-emu/lfd.c4
-rw-r--r--arch/powerpc/math-emu/lfs.c19
-rw-r--r--arch/powerpc/math-emu/math.c8
-rw-r--r--arch/powerpc/math-emu/mcrfs.c3
-rw-r--r--arch/powerpc/math-emu/mffs.c3
-rw-r--r--arch/powerpc/math-emu/mtfsb0.c3
-rw-r--r--arch/powerpc/math-emu/mtfsb1.c3
-rw-r--r--arch/powerpc/math-emu/mtfsf.c20
-rw-r--r--arch/powerpc/math-emu/mtfsfi.c3
-rw-r--r--arch/powerpc/math-emu/op-1.h245
-rw-r--r--arch/powerpc/math-emu/op-2.h434
-rw-r--r--arch/powerpc/math-emu/op-4.h317
-rw-r--r--arch/powerpc/math-emu/op-common.h688
-rw-r--r--arch/powerpc/math-emu/single.h66
-rw-r--r--arch/powerpc/math-emu/soft-fp.h104
-rw-r--r--arch/powerpc/math-emu/stfs.c19
-rw-r--r--arch/powerpc/math-emu/types.c51
-rw-r--r--arch/powerpc/math-emu/udivmodti4.c2
-rw-r--r--arch/powerpc/mm/fsl_booke_mmu.c5
-rw-r--r--arch/powerpc/mm/gup.c7
-rw-r--r--arch/powerpc/mm/hash_low_32.S122
-rw-r--r--arch/powerpc/mm/hash_utils_64.c8
-rw-r--r--arch/powerpc/mm/hugetlbpage.c59
-rw-r--r--arch/powerpc/mm/init_64.c4
-rw-r--r--arch/powerpc/mm/mem.c5
-rw-r--r--arch/powerpc/mm/numa.c185
-rw-r--r--arch/powerpc/mm/pgtable_32.c4
-rw-r--r--arch/powerpc/mm/tlb_32.c1
-rw-r--r--arch/powerpc/oprofile/cell/vma_map.c2
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c4
-rw-r--r--arch/powerpc/platforms/44x/Kconfig42
-rw-r--r--arch/powerpc/platforms/44x/Makefile8
-rw-r--r--arch/powerpc/platforms/44x/bamboo.c62
-rw-r--r--arch/powerpc/platforms/44x/canyonlands.c63
-rw-r--r--arch/powerpc/platforms/44x/katmai.c62
-rw-r--r--arch/powerpc/platforms/44x/ppc44x_simple.c88
-rw-r--r--arch/powerpc/platforms/44x/rainier.c62
-rw-r--r--arch/powerpc/platforms/44x/sequoia.c63
-rw-r--r--arch/powerpc/platforms/44x/taishan.c72
-rw-r--r--arch/powerpc/platforms/512x/Kconfig2
-rw-r--r--arch/powerpc/platforms/512x/mpc5121_ads.c10
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_common.c5
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c13
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig8
-rw-r--r--arch/powerpc/platforms/82xx/Makefile1
-rw-r--r--arch/powerpc/platforms/82xx/mgcoge.c129
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig5
-rw-r--r--arch/powerpc/platforms/83xx/mpc837x_mds.c8
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig1
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c1
-rw-r--r--arch/powerpc/platforms/85xx/sbc8560.c3
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig9
-rw-r--r--arch/powerpc/platforms/86xx/Makefile1
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.c258
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.h11
-rw-r--r--arch/powerpc/platforms/86xx/gef_sbc610.c221
-rw-r--r--arch/powerpc/platforms/86xx/mpc8610_hpcd.c1
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c8
-rw-r--r--arch/powerpc/platforms/86xx/sbc8641d.c8
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig6
-rw-r--r--arch/powerpc/platforms/8xx/Makefile1
-rw-r--r--arch/powerpc/platforms/8xx/mgsuvd.c92
-rw-r--r--arch/powerpc/platforms/Kconfig21
-rw-r--r--arch/powerpc/platforms/Kconfig.cputype17
-rw-r--r--arch/powerpc/platforms/cell/iommu.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c11
-rw-r--r--arch/powerpc/platforms/chrp/pci.c4
-rw-r--r--arch/powerpc/platforms/chrp/time.c24
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c1
-rw-r--r--arch/powerpc/platforms/iseries/exception.S23
-rw-r--r--arch/powerpc/platforms/iseries/mf.c26
-rw-r--r--arch/powerpc/platforms/maple/time.c24
-rw-r--r--arch/powerpc/platforms/powermac/feature.c2
-rw-r--r--arch/powerpc/platforms/powermac/smp.c4
-rw-r--r--arch/powerpc/platforms/powermac/time.c3
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c2
-rw-r--r--arch/powerpc/platforms/pseries/cmm.c4
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c2
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c6
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c26
-rw-r--r--arch/powerpc/platforms/pseries/smp.c32
-rw-r--r--arch/powerpc/platforms/pseries/xics.c550
-rw-r--r--arch/powerpc/platforms/pseries/xics.h12
-rw-r--r--arch/powerpc/sysdev/Kconfig6
-rw-r--r--arch/powerpc/sysdev/Makefile5
-rw-r--r--arch/powerpc/sysdev/cpm1.c74
-rw-r--r--arch/powerpc/sysdev/fsl_lbc.c53
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c109
-rw-r--r--arch/powerpc/sysdev/fsl_msi.h8
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c58
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c85
-rw-r--r--arch/powerpc/sysdev/fsl_soc.h8
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c171
-rw-r--r--arch/powerpc/sysdev/mpic.h2
-rw-r--r--arch/powerpc/sysdev/mpic_msi.c123
-rw-r--r--arch/powerpc/sysdev/mpic_pasemi_msi.c24
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c22
-rw-r--r--arch/powerpc/sysdev/msi_bitmap.c247
-rw-r--r--arch/powerpc/sysdev/ppc4xx_pci.c32
-rw-r--r--arch/powerpc/sysdev/qe_lib/Kconfig9
-rw-r--r--arch/s390/kernel/compat_linux.c102
-rw-r--r--arch/s390/kernel/compat_linux.h4
-rw-r--r--arch/s390/kernel/compat_wrapper.S12
-rw-r--r--arch/s390/kernel/syscalls.S4
-rw-r--r--arch/sparc64/kernel/iommu.c7
-rw-r--r--arch/sparc64/kernel/iommu_common.h14
-rw-r--r--arch/sparc64/kernel/pci_sun4v.c7
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c97
-rw-r--r--arch/sparc64/kernel/systbls.S4
-rw-r--r--arch/sparc64/kernel/us3_cpufreq.c1
-rw-r--r--arch/um/kernel/exec.c12
-rw-r--r--arch/um/os-Linux/Makefile3
-rw-r--r--arch/um/os-Linux/tty_log.c217
-rw-r--r--arch/x86/Kconfig23
-rw-r--r--arch/x86/boot/video-vesa.c9
-rw-r--r--arch/x86/ia32/ia32entry.S4
-rw-r--r--arch/x86/ia32/sys_ia32.c99
-rw-r--r--arch/x86/kernel/amd_iommu.c9
-rw-r--r--arch/x86/kernel/pci-calgary_64.c18
-rw-r--r--arch/x86/kernel/pci-dma.c4
-rw-r--r--arch/x86/kernel/pci-gart_64.c8
-rw-r--r--arch/x86/kernel/rtc.c22
-rw-r--r--arch/x86/kernel/smpboot.c14
-rw-r--r--arch/x86/kvm/x86.c2
-rw-r--r--drivers/acpi/glue.c112
-rw-r--r--drivers/ata/pata_of_platform.c2
-rw-r--r--drivers/base/Kconfig2
-rw-r--r--drivers/base/firmware_class.c24
-rw-r--r--drivers/base/platform.c31
-rw-r--r--drivers/base/power/main.c7
-rw-r--r--drivers/block/ataflop.c4
-rw-r--r--drivers/block/floppy.c2
-rw-r--r--drivers/block/viodasd.c3
-rw-r--r--drivers/char/Kconfig9
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/ds1286.c4
-rw-r--r--drivers/char/hvc_console.c10
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c2
-rw-r--r--drivers/char/moxa.c2
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/rtc.c2
-rw-r--r--drivers/char/sysrq.c31
-rw-r--r--drivers/char/tpm/tpm.c36
-rw-r--r--drivers/char/tty_io.c5
-rw-r--r--drivers/char/vt.c7
-rw-r--r--drivers/edac/i5000_edac.c196
-rw-r--r--drivers/edac/i82443bxgx_edac.c63
-rw-r--r--drivers/edac/mpc85xx_edac.c33
-rw-r--r--drivers/gpio/gpiolib.c111
-rw-r--r--drivers/gpio/max7301.c24
-rw-r--r--drivers/gpio/max732x.c5
-rw-r--r--drivers/gpio/mcp23s08.c5
-rw-r--r--drivers/gpio/pca953x.c5
-rw-r--r--drivers/gpio/pcf857x.c5
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c4
-rw-r--r--drivers/hid/Kconfig221
-rw-r--r--drivers/hid/Makefile35
-rw-r--r--drivers/hid/hid-a4tech.c162
-rw-r--r--drivers/hid/hid-apple.c484
-rw-r--r--drivers/hid/hid-belkin.c105
-rw-r--r--drivers/hid/hid-bright.c71
-rw-r--r--drivers/hid/hid-cherry.c87
-rw-r--r--drivers/hid/hid-chicony.c80
-rw-r--r--drivers/hid/hid-core.c1181
-rw-r--r--drivers/hid/hid-cypress.c158
-rw-r--r--drivers/hid/hid-dell.c75
-rw-r--r--drivers/hid/hid-dummy.c72
-rw-r--r--drivers/hid/hid-ezkey.c95
-rw-r--r--drivers/hid/hid-gyration.c96
-rw-r--r--drivers/hid/hid-ids.h404
-rw-r--r--drivers/hid/hid-input-quirks.c484
-rw-r--r--drivers/hid/hid-input.c915
-rw-r--r--drivers/hid/hid-lg.c342
-rw-r--r--drivers/hid/hid-lg.h18
-rw-r--r--drivers/hid/hid-lg2ff.c (renamed from drivers/hid/usbhid/hid-lg2ff.c)14
-rw-r--r--drivers/hid/hid-lgff.c (renamed from drivers/hid/usbhid/hid-lgff.c)34
-rw-r--r--drivers/hid/hid-microsoft.c219
-rw-r--r--drivers/hid/hid-monterey.c82
-rw-r--r--drivers/hid/hid-petalynx.c122
-rw-r--r--drivers/hid/hid-pl.c (renamed from drivers/hid/usbhid/hid-plff.c)83
-rw-r--r--drivers/hid/hid-samsung.c100
-rw-r--r--drivers/hid/hid-sony.c110
-rw-r--r--drivers/hid/hid-sunplus.c82
-rw-r--r--drivers/hid/hid-tmff.c (renamed from drivers/hid/usbhid/hid-tmff.c)138
-rw-r--r--drivers/hid/hid-zpff.c (renamed from drivers/hid/usbhid/hid-zpff.c)71
-rw-r--r--drivers/hid/hidraw.c8
-rw-r--r--drivers/hid/usbhid/Kconfig75
-rw-r--r--drivers/hid/usbhid/Makefile18
-rw-r--r--drivers/hid/usbhid/hid-core.c463
-rw-r--r--drivers/hid/usbhid/hid-ff.c95
-rw-r--r--drivers/hid/usbhid/hid-pidff.c5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c934
-rw-r--r--drivers/hid/usbhid/hiddev.c20
-rw-r--r--drivers/hid/usbhid/usbhid.h4
-rw-r--r--drivers/hid/usbhid/usbkbd.c12
-rw-r--r--drivers/hid/usbhid/usbmouse.c8
-rw-r--r--drivers/hwmon/ams/ams.h2
-rw-r--r--drivers/hwmon/dme1737.c320
-rw-r--r--drivers/i2c/busses/Kconfig20
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-highlander.c498
-rw-r--r--drivers/i2c/busses/i2c-mpc.c1
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c39
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c22
-rw-r--r--drivers/i2c/busses/i2c-viapro.c17
-rw-r--r--drivers/i2c/chips/Kconfig11
-rw-r--r--drivers/i2c/chips/Makefile1
-rw-r--r--drivers/i2c/chips/isp1301_omap.c141
-rw-r--r--drivers/i2c/chips/mcu_mpc8349emitx.c209
-rw-r--r--drivers/i2c/chips/tps65010.c12
-rw-r--r--drivers/i2c/i2c-core.c35
-rw-r--r--drivers/ide/Kconfig2
-rw-r--r--drivers/input/joystick/xpad.c4
-rw-r--r--drivers/input/keyboard/omap-keypad.c27
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c10
-rw-r--r--drivers/input/serio/hp_sdc.c2
-rw-r--r--drivers/input/serio/i8042-io.h2
-rw-r--r--drivers/isdn/mISDN/dsp_cmx.c4
-rw-r--r--drivers/isdn/mISDN/timerdev.c2
-rw-r--r--drivers/md/Kconfig14
-rw-r--r--drivers/message/i2o/Makefile2
-rw-r--r--drivers/message/i2o/device.c2
-rw-r--r--drivers/message/i2o/exec-osm.c4
-rw-r--r--drivers/message/i2o/i2o_config.c31
-rw-r--r--drivers/message/i2o/iop.c2
-rw-r--r--drivers/message/i2o/memory.c313
-rw-r--r--drivers/message/i2o/pci.c16
-rw-r--r--drivers/mfd/Kconfig38
-rw-r--r--drivers/mfd/Makefile5
-rw-r--r--drivers/mfd/wm8350-core.c1273
-rw-r--r--drivers/mfd/wm8350-gpio.c222
-rw-r--r--drivers/mfd/wm8350-i2c.c120
-rw-r--r--drivers/mfd/wm8350-regmap.c1347
-rw-r--r--drivers/mfd/wm8400-core.c455
-rw-r--r--drivers/misc/Kconfig3
-rw-r--r--drivers/misc/hp-wmi.c2
-rw-r--r--drivers/misc/sgi-gru/gru.h4
-rw-r--r--drivers/misc/sgi-gru/gru_instructions.h10
-rw-r--r--drivers/misc/sgi-gru/grufault.c11
-rw-r--r--drivers/misc/sgi-gru/grufile.c8
-rw-r--r--drivers/misc/sgi-gru/gruhandles.h5
-rw-r--r--drivers/misc/sgi-gru/grukservices.c3
-rw-r--r--drivers/misc/sgi-gru/grumain.c29
-rw-r--r--drivers/mtd/nand/ams-delta.c4
-rw-r--r--drivers/net/3c501.c12
-rw-r--r--drivers/net/3c509.c2
-rw-r--r--drivers/net/3c515.c2
-rw-r--r--drivers/net/Kconfig2
-rw-r--r--drivers/net/appletalk/cops.c2
-rw-r--r--drivers/net/cs89x0.c13
-rw-r--r--drivers/net/cxgb3/adapter.h2
-rw-r--r--drivers/net/cxgb3/ael1002.c2
-rw-r--r--drivers/net/cxgb3/common.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_ctl_defs.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_defs.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_ioctl.h2
-rw-r--r--drivers/net/cxgb3/cxgb3_main.c2
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.c2
-rw-r--r--drivers/net/cxgb3/cxgb3_offload.h2
-rw-r--r--drivers/net/cxgb3/firmware_exports.h2
-rw-r--r--drivers/net/cxgb3/l2t.c2
-rw-r--r--drivers/net/cxgb3/l2t.h2
-rw-r--r--drivers/net/cxgb3/mc5.c2
-rw-r--r--drivers/net/cxgb3/sge.c2
-rw-r--r--drivers/net/cxgb3/t3_cpl.h2
-rw-r--r--drivers/net/cxgb3/t3_hw.c2
-rw-r--r--drivers/net/cxgb3/t3cdev.h2
-rw-r--r--drivers/net/cxgb3/version.h4
-rw-r--r--drivers/net/cxgb3/vsc8211.c2
-rw-r--r--drivers/net/cxgb3/xgmac.c2
-rw-r--r--drivers/net/eexpress.c2
-rw-r--r--drivers/net/enic/enic_main.c1
-rw-r--r--drivers/net/ibm_newemac/Kconfig12
-rw-r--r--drivers/net/ibm_newemac/core.c42
-rw-r--r--drivers/net/ibm_newemac/core.h6
-rw-r--r--drivers/net/ibm_newemac/mal.c60
-rw-r--r--drivers/net/ibm_newemac/mal.h34
-rw-r--r--drivers/net/ibm_newemac/phy.c84
-rw-r--r--drivers/net/ibm_newemac/phy.h2
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/jme.c1
-rw-r--r--drivers/net/macmace.c2
-rw-r--r--drivers/net/pcmcia/3c589_cs.c2
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c2
-rw-r--r--drivers/net/phy/mdio_bus.c1
-rw-r--r--drivers/net/phy/phy_device.c1
-rw-r--r--drivers/net/qlge/qlge.h2
-rw-r--r--drivers/net/qlge/qlge_main.c1
-rw-r--r--drivers/net/tlan.c3
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tulip/de2104x.c1
-rw-r--r--drivers/net/tulip/dmfe.c4
-rw-r--r--drivers/net/via-velocity.c2
-rw-r--r--drivers/net/wan/z85230.c3
-rw-r--r--drivers/net/wan/z85230.h2
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan.p.h2
-rw-r--r--drivers/net/xen-netfront.c2
-rw-r--r--drivers/nubus/nubus.c2
-rw-r--r--drivers/of/base.c136
-rw-r--r--drivers/of/gpio.c81
-rw-r--r--drivers/parport/ChangeLog2
-rw-r--r--drivers/parport/ieee1284.c2
-rw-r--r--drivers/parport/probe.c2
-rw-r--r--drivers/parport/share.c2
-rw-r--r--drivers/pci/hotplug/rpaphp_slot.c4
-rw-r--r--drivers/pnp/base.h2
-rw-r--r--drivers/pnp/core.c1
-rw-r--r--drivers/pnp/isapnp/core.c2
-rw-r--r--drivers/pnp/pnpbios/core.c4
-rw-r--r--drivers/pnp/quirks.c2
-rw-r--r--drivers/pnp/resource.c4
-rw-r--r--drivers/power/olpc_battery.c20
-rw-r--r--drivers/regulator/Kconfig24
-rw-r--r--drivers/regulator/Makefile3
-rw-r--r--drivers/regulator/bq24022.c21
-rw-r--r--drivers/regulator/core.c508
-rw-r--r--drivers/regulator/da903x.c513
-rw-r--r--drivers/regulator/wm8350-regulator.c1431
-rw-r--r--drivers/regulator/wm8400-regulator.c368
-rw-r--r--drivers/rtc/Kconfig39
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/rtc-at91rm9200.c4
-rw-r--r--drivers/rtc/rtc-cmos.c122
-rw-r--r--drivers/rtc/rtc-dev.c12
-rw-r--r--drivers/rtc/rtc-ds1286.c409
-rw-r--r--drivers/rtc/rtc-ds1307.c308
-rw-r--r--drivers/rtc/rtc-ds1374.c21
-rw-r--r--drivers/rtc/rtc-ds1511.c13
-rw-r--r--drivers/rtc/rtc-ds1553.c12
-rw-r--r--drivers/rtc/rtc-ds1672.c114
-rw-r--r--drivers/rtc/rtc-ds3234.c290
-rw-r--r--drivers/rtc/rtc-m41t80.c43
-rw-r--r--drivers/rtc/rtc-m48t35.c234
-rw-r--r--drivers/rtc/rtc-max6900.c223
-rw-r--r--drivers/rtc/rtc-pcf8563.c58
-rw-r--r--drivers/rtc/rtc-pl030.c11
-rw-r--r--drivers/rtc/rtc-pl031.c14
-rw-r--r--drivers/rtc/rtc-rs5c372.c228
-rw-r--r--drivers/rtc/rtc-sh.c7
-rw-r--r--drivers/rtc/rtc-stk17ta8.c12
-rw-r--r--drivers/s390/net/claw.c2
-rw-r--r--drivers/s390/net/ctcm_mpc.c2
-rw-r--r--drivers/scsi/Kconfig9
-rw-r--r--drivers/scsi/atari_dma_emul.c468
-rw-r--r--drivers/scsi/atari_scsi.c27
-rw-r--r--drivers/serial/8250.c3
-rw-r--r--drivers/serial/Kconfig36
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c3
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c6
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c6
-rw-r--r--drivers/serial/mpc52xx_uart.c181
-rw-r--r--drivers/serial/ucc_uart.c4
-rw-r--r--drivers/spi/mpc52xx_psc_spi.c61
-rw-r--r--drivers/spi/orion_spi.c5
-rw-r--r--drivers/spi/pxa2xx_spi.c54
-rw-r--r--drivers/spi/spi.c24
-rw-r--r--drivers/spi/spi_s3c24xx.c6
-rw-r--r--drivers/telephony/ixj.c2
-rw-r--r--drivers/video/Kconfig109
-rw-r--r--drivers/video/Makefile3
-rw-r--r--drivers/video/atmel_lcdfb.c7
-rw-r--r--drivers/video/aty/radeon_accel.c313
-rw-r--r--drivers/video/aty/radeon_backlight.c2
-rw-r--r--drivers/video/aty/radeon_base.c35
-rw-r--r--drivers/video/aty/radeon_i2c.c4
-rw-r--r--drivers/video/aty/radeon_pm.c6
-rw-r--r--drivers/video/aty/radeonfb.h53
-rw-r--r--drivers/video/carminefb.c2
-rw-r--r--drivers/video/cirrusfb.c577
-rw-r--r--drivers/video/console/fbcon.c43
-rw-r--r--drivers/video/console/mdacon.c2
-rw-r--r--drivers/video/console/sticon.c4
-rw-r--r--drivers/video/console/vgacon.c43
-rw-r--r--drivers/video/efifb.c191
-rw-r--r--drivers/video/fbmon.c8
-rw-r--r--drivers/video/imacfb.c376
-rw-r--r--drivers/video/intelfb/intelfb.h7
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c1
-rw-r--r--drivers/video/intelfb/intelfbdrv.c7
-rw-r--r--drivers/video/intelfb/intelfbhw.c7
-rw-r--r--drivers/video/matrox/matroxfb_base.c9
-rw-r--r--drivers/video/metronomefb.c2
-rw-r--r--drivers/video/neofb.c60
-rw-r--r--drivers/video/omap/lcd_inn1610.c22
-rw-r--r--drivers/video/omap/lcd_osk.c10
-rw-r--r--drivers/video/omap/lcd_sx1.c99
-rw-r--r--drivers/video/s1d13xxxfb.c23
-rw-r--r--drivers/video/tdfxfb.c48
-rw-r--r--drivers/video/tmiofb.c1050
-rw-r--r--drivers/video/uvesafb.c11
-rw-r--r--drivers/video/vga16fb.c11
-rw-r--r--drivers/video/via/Makefile7
-rw-r--r--drivers/video/via/accel.c279
-rw-r--r--drivers/video/via/accel.h169
-rw-r--r--drivers/video/via/chip.h190
-rw-r--r--drivers/video/via/debug.h41
-rw-r--r--drivers/video/via/dvi.c682
-rw-r--r--drivers/video/via/dvi.h64
-rw-r--r--drivers/video/via/global.c60
-rw-r--r--drivers/video/via/global.h90
-rw-r--r--drivers/video/via/hw.c2865
-rw-r--r--drivers/video/via/hw.h933
-rw-r--r--drivers/video/via/iface.c78
-rw-r--r--drivers/video/via/iface.h38
-rw-r--r--drivers/video/via/ioctl.c112
-rw-r--r--drivers/video/via/ioctl.h210
-rw-r--r--drivers/video/via/lcd.c1821
-rw-r--r--drivers/video/via/lcd.h94
-rw-r--r--drivers/video/via/lcdtbl.h591
-rw-r--r--drivers/video/via/share.h1105
-rw-r--r--drivers/video/via/tbl1636.c71
-rw-r--r--drivers/video/via/tbl1636.h34
-rw-r--r--drivers/video/via/tblDPASetting.c109
-rw-r--r--drivers/video/via/tblDPASetting.h47
-rw-r--r--drivers/video/via/via_i2c.c177
-rw-r--r--drivers/video/via/via_i2c.h46
-rw-r--r--drivers/video/via/via_utility.c253
-rw-r--r--drivers/video/via/via_utility.h35
-rw-r--r--drivers/video/via/viafbdev.c2571
-rw-r--r--drivers/video/via/viafbdev.h112
-rw-r--r--drivers/video/via/viamode.c1086
-rw-r--r--drivers/video/via/viamode.h177
-rw-r--r--drivers/video/via/vt1636.c306
-rw-r--r--drivers/video/via/vt1636.h44
-rw-r--r--drivers/w1/masters/ds1wm.c10
-rw-r--r--drivers/w1/masters/ds2490.c348
-rw-r--r--drivers/w1/slaves/w1_ds2431.c312
-rw-r--r--drivers/w1/slaves/w1_therm.c72
-rw-r--r--drivers/w1/w1.c423
-rw-r--r--drivers/w1/w1.h34
-rw-r--r--drivers/w1/w1_family.c13
-rw-r--r--drivers/w1/w1_family.h3
-rw-r--r--drivers/w1/w1_int.c88
-rw-r--r--drivers/w1/w1_io.c85
-rw-r--r--fs/Kconfig64
-rw-r--r--fs/Kconfig.binfmt2
-rw-r--r--fs/Makefile6
-rw-r--r--fs/afs/file.c4
-rw-r--r--fs/afs/internal.h8
-rw-r--r--fs/afs/write.c131
-rw-r--r--fs/autofs4/Makefile2
-rw-r--r--fs/autofs4/autofs_i.h44
-rw-r--r--fs/autofs4/dev-ioctl.c863
-rw-r--r--fs/autofs4/expire.c18
-rw-r--r--fs/autofs4/init.c11
-rw-r--r--fs/autofs4/inode.c8
-rw-r--r--fs/autofs4/waitq.c42
-rw-r--r--fs/befs/befs_fs_types.h4
-rw-r--r--fs/befs/linuxvfs.c4
-rw-r--r--fs/befs/super.c6
-rw-r--r--fs/binfmt_elf_fdpic.c85
-rw-r--r--fs/binfmt_em86.c2
-rw-r--r--fs/binfmt_flat.c6
-rw-r--r--fs/binfmt_misc.c4
-rw-r--r--fs/binfmt_script.c5
-rw-r--r--fs/binfmt_som.c2
-rw-r--r--fs/compat.c41
-rw-r--r--fs/direct-io.c4
-rw-r--r--fs/dquot.c2
-rw-r--r--fs/ecryptfs/Makefile2
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h28
-rw-r--r--fs/ecryptfs/file.c17
-rw-r--r--fs/ecryptfs/keystore.c32
-rw-r--r--fs/ecryptfs/main.c19
-rw-r--r--fs/ecryptfs/messaging.c118
-rw-r--r--fs/ecryptfs/mmap.c81
-rw-r--r--fs/ecryptfs/netlink.c249
-rw-r--r--fs/eventpoll.c9
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext2/balloc.c3
-rw-r--r--fs/ext2/dir.c60
-rw-r--r--fs/fs-writeback.c2
-rw-r--r--fs/hfs/catalog.c4
-rw-r--r--fs/hfsplus/bitmap.c12
-rw-r--r--fs/hfsplus/catalog.c5
-rw-r--r--fs/hfsplus/super.c2
-rw-r--r--fs/lockd/Makefile2
-rw-r--r--fs/lockd/clntlock.c13
-rw-r--r--fs/lockd/grace.c59
-rw-r--r--fs/lockd/host.c350
-rw-r--r--fs/lockd/mon.c2
-rw-r--r--fs/lockd/svc.c88
-rw-r--r--fs/lockd/svc4proc.c31
-rw-r--r--fs/lockd/svclock.c18
-rw-r--r--fs/lockd/svcproc.c31
-rw-r--r--fs/lockd/svcsubs.c2
-rw-r--r--fs/lockd/xdr.c2
-rw-r--r--fs/lockd/xdr4.c2
-rw-r--r--fs/mpage.c2
-rw-r--r--fs/nfs/callback.c3
-rw-r--r--fs/nfsd/lockd.c1
-rw-r--r--fs/nfsd/nfs3proc.c8
-rw-r--r--fs/nfsd/nfs4callback.c7
-rw-r--r--fs/nfsd/nfs4proc.c8
-rw-r--r--fs/nfsd/nfs4state.c34
-rw-r--r--fs/nfsd/nfs4xdr.c171
-rw-r--r--fs/nfsd/nfsctl.c5
-rw-r--r--fs/nfsd/nfsfh.c30
-rw-r--r--fs/nfsd/nfsproc.c6
-rw-r--r--fs/nfsd/nfssvc.c20
-rw-r--r--fs/nfsd/vfs.c63
-rw-r--r--fs/ocfs2/Makefile3
-rw-r--r--fs/ocfs2/alloc.c913
-rw-r--r--fs/ocfs2/alloc.h86
-rw-r--r--fs/ocfs2/aops.c60
-rw-r--r--fs/ocfs2/buffer_head_io.c134
-rw-r--r--fs/ocfs2/buffer_head_io.h23
-rw-r--r--fs/ocfs2/cluster/masklog.c1
-rw-r--r--fs/ocfs2/cluster/masklog.h1
-rw-r--r--fs/ocfs2/dir.c109
-rw-r--r--fs/ocfs2/dlmglue.c9
-rw-r--r--fs/ocfs2/extent_map.c70
-rw-r--r--fs/ocfs2/extent_map.h4
-rw-r--r--fs/ocfs2/file.c333
-rw-r--r--fs/ocfs2/file.h32
-rw-r--r--fs/ocfs2/inode.c87
-rw-r--r--fs/ocfs2/inode.h6
-rw-r--r--fs/ocfs2/ioctl.c3
-rw-r--r--fs/ocfs2/journal.c89
-rw-r--r--fs/ocfs2/journal.h52
-rw-r--r--fs/ocfs2/localalloc.c384
-rw-r--r--fs/ocfs2/localalloc.h4
-rw-r--r--fs/ocfs2/locks.c15
-rw-r--r--fs/ocfs2/locks.h1
-rw-r--r--fs/ocfs2/namei.c101
-rw-r--r--fs/ocfs2/ocfs2.h56
-rw-r--r--fs/ocfs2/ocfs2_fs.h220
-rw-r--r--fs/ocfs2/ocfs2_jbd_compat.h82
-rw-r--r--fs/ocfs2/resize.c11
-rw-r--r--fs/ocfs2/slot_map.c7
-rw-r--r--fs/ocfs2/stack_user.c33
-rw-r--r--fs/ocfs2/stackglue.c20
-rw-r--r--fs/ocfs2/stackglue.h19
-rw-r--r--fs/ocfs2/suballoc.c248
-rw-r--r--fs/ocfs2/suballoc.h26
-rw-r--r--fs/ocfs2/super.c62
-rw-r--r--fs/ocfs2/symlink.c18
-rw-r--r--fs/ocfs2/uptodate.c38
-rw-r--r--fs/ocfs2/uptodate.h3
-rw-r--r--fs/ocfs2/xattr.c4832
-rw-r--r--fs/ocfs2/xattr.h68
-rw-r--r--fs/partitions/acorn.c10
-rw-r--r--fs/partitions/check.c17
-rw-r--r--fs/proc/proc_misc.c30
-rw-r--r--fs/reiserfs/procfs.c3
-rw-r--r--fs/reiserfs/xattr.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--include/acpi/acmacros.h6
-rw-r--r--include/acpi/platform/acgcc.h2
-rw-r--r--include/asm-generic/bug.h2
-rw-r--r--include/asm-generic/gpio.h18
-rw-r--r--include/asm-h8300/timer.h25
-rw-r--r--include/asm-m68k/atarihw.h1
-rw-r--r--include/asm-m68k/dma-mapping.h16
-rw-r--r--include/asm-m68k/dma.h4
-rw-r--r--include/asm-m68k/entry.h2
-rw-r--r--include/asm-m68k/io.h66
-rw-r--r--include/asm-m68k/pci.h47
-rw-r--r--include/asm-m68k/virtconvert.h6
-rw-r--r--include/asm-x86/es7000/apic.h2
-rw-r--r--include/asm-x86/iommu.h2
-rw-r--r--include/asm-x86/summit/apic.h2
-rw-r--r--include/linux/aio.h9
-rw-r--r--include/linux/auto_dev-ioctl.h157
-rw-r--r--include/linux/auto_fs4.h7
-rw-r--r--include/linux/binfmts.h5
-rw-r--r--include/linux/cgroup.h3
-rw-r--r--include/linux/clk.h4
-rw-r--r--include/linux/compat.h6
-rw-r--r--include/linux/console_struct.h1
-rw-r--r--include/linux/ds1286.h2
-rw-r--r--include/linux/ext2_fs.h2
-rw-r--r--include/linux/ext3_fs.h4
-rw-r--r--include/linux/ext3_jbd.h14
-rw-r--r--include/linux/fs.h65
-rw-r--r--include/linux/gpio.h3
-rw-r--r--include/linux/hid.h373
-rw-r--r--include/linux/hiddev.h46
-rw-r--r--include/linux/i2o.h292
-rw-r--r--include/linux/if_ether.h2
-rw-r--r--include/linux/if_fddi.h2
-rw-r--r--include/linux/if_hippi.h2
-rw-r--r--include/linux/igmp.h2
-rw-r--r--include/linux/init.h4
-rw-r--r--include/linux/iommu-helper.h3
-rw-r--r--include/linux/ioport.h7
-rw-r--r--include/linux/jbd.h4
-rw-r--r--include/linux/jbd2.h4
-rw-r--r--include/linux/journal-head.h2
-rw-r--r--include/linux/kallsyms.h8
-rw-r--r--include/linux/kernel.h25
-rw-r--r--include/linux/kmod.h3
-rw-r--r--include/linux/lockd/bind.h11
-rw-r--r--include/linux/lockd/lockd.h137
-rw-r--r--include/linux/lockd/xdr.h2
-rw-r--r--include/linux/mfd/tmio.h19
-rw-r--r--include/linux/mfd/wm8350/audio.h598
-rw-r--r--include/linux/mfd/wm8350/comparator.h167
-rw-r--r--include/linux/mfd/wm8350/core.h631
-rw-r--r--include/linux/mfd/wm8350/gpio.h342
-rw-r--r--include/linux/mfd/wm8350/pmic.h741
-rw-r--r--include/linux/mfd/wm8350/rtc.h266
-rw-r--r--include/linux/mfd/wm8350/supply.h111
-rw-r--r--include/linux/mfd/wm8350/wdt.h28
-rw-r--r--include/linux/mfd/wm8400-audio.h1186
-rw-r--r--include/linux/mfd/wm8400-private.h936
-rw-r--r--include/linux/mfd/wm8400.h40
-rw-r--r--include/linux/mod_devicetable.h10
-rw-r--r--include/linux/mount.h2
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/linux/nfsd/nfsd.h3
-rw-r--r--include/linux/of.h3
-rw-r--r--include/linux/parport.h2
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/linux/pid_namespace.h6
-rw-r--r--include/linux/pm.h2
-rw-r--r--include/linux/pnp.h6
-rw-r--r--include/linux/proc_fs.h1
-rw-r--r--include/linux/profile.h8
-rw-r--r--include/linux/quota.h2
-rw-r--r--include/linux/quotaops.h3
-rw-r--r--include/linux/regulator/driver.h10
-rw-r--r--include/linux/regulator/machine.h30
-rw-r--r--include/linux/reiserfs_fs.h2
-rw-r--r--include/linux/rtmutex.h2
-rw-r--r--include/linux/spi/orion_spi.h1
-rw-r--r--include/linux/sunrpc/clnt.h5
-rw-r--r--include/linux/sunrpc/svc.h19
-rw-r--r--include/linux/sunrpc/svc_rdma.h27
-rw-r--r--include/linux/sunrpc/svcsock.h5
-rw-r--r--include/linux/swiotlb.h83
-rw-r--r--include/linux/sysctl.h2
-rw-r--r--include/linux/task_io_accounting.h2
-rw-r--r--include/linux/telephony.h4
-rw-r--r--include/linux/time.h2
-rw-r--r--include/linux/wait.h9
-rw-r--r--include/math-emu/op-2.h2
-rw-r--r--include/math-emu/op-common.h12
-rw-r--r--include/math-emu/soft-fp.h19
-rw-r--r--include/media/saa7146.h2
-rw-r--r--include/net/9p/9p.h4
-rw-r--r--include/net/bluetooth/bluetooth.h4
-rw-r--r--include/net/ieee80211.h2
-rw-r--r--include/net/ip.h2
-rw-r--r--include/net/ip_vs.h4
-rw-r--r--include/net/irda/irda.h2
-rw-r--r--include/net/ndisc.h5
-rw-r--r--include/net/sctp/sctp.h2
-rw-r--r--include/video/cyblafb.h2
-rw-r--r--include/video/neomagic.h1
-rw-r--r--include/video/radeon.h23
-rw-r--r--include/video/s1d13xxxfb.h3
-rw-r--r--init/Kconfig8
-rw-r--r--init/do_mounts_md.c40
-rw-r--r--init/do_mounts_rd.c2
-rw-r--r--init/initramfs.c53
-rw-r--r--init/main.c2
-rw-r--r--ipc/ipc_sysctl.c9
-rw-r--r--ipc/sem.c2
-rw-r--r--kernel/cgroup.c4
-rw-r--r--kernel/compat.c58
-rw-r--r--kernel/dma.c2
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/kallsyms.c1
-rw-r--r--kernel/kmod.c65
-rw-r--r--kernel/kprobes.c2
-rw-r--r--kernel/ksysfs.c35
-rw-r--r--kernel/module.c12
-rw-r--r--kernel/panic.c65
-rw-r--r--kernel/power/disk.c11
-rw-r--r--kernel/power/main.c7
-rw-r--r--kernel/power/user.c10
-rw-r--r--kernel/printk.c4
-rw-r--r--kernel/profile.c41
-rw-r--r--kernel/resource.c41
-rw-r--r--kernel/softlockup.c2
-rw-r--r--kernel/sys.c34
-rw-r--r--kernel/sys_ni.c6
-rw-r--r--kernel/sysctl.c104
-rw-r--r--kernel/time/Kconfig1
-rw-r--r--kernel/utsname_sysctl.c5
-rw-r--r--kernel/wait.c14
-rw-r--r--kernel/workqueue.c2
-rw-r--r--lib/Kconfig4
-rw-r--r--lib/iommu-helper.c9
-rw-r--r--lib/vsprintf.c12
-rw-r--r--mm/Kconfig4
-rw-r--r--mm/bootmem.c2
-rw-r--r--mm/fadvise.c2
-rw-r--r--mm/filemap.c3
-rw-r--r--mm/hugetlb.c23
-rw-r--r--mm/page-writeback.c2
-rw-r--r--mm/page_alloc.c2
-rw-r--r--mm/pdflush.c2
-rw-r--r--mm/readahead.c2
-rw-r--r--mm/truncate.c2
-rw-r--r--net/802/psnap.c2
-rw-r--r--net/appletalk/ddp.c4
-rw-r--r--net/bluetooth/hidp/core.c214
-rw-r--r--net/bluetooth/hidp/hidp.h2
-rw-r--r--net/core/datagram.c2
-rw-r--r--net/core/dev_mcast.c2
-rw-r--r--net/core/pktgen.c8
-rw-r--r--net/core/skbuff.c2
-rw-r--r--net/core/stream.c2
-rw-r--r--net/decnet/dn_dev.c4
-rw-r--r--net/decnet/sysctl_net_decnet.c4
-rw-r--r--net/dsa/Kconfig2
-rw-r--r--net/ipv4/devinet.c7
-rw-r--r--net/ipv4/icmp.c2
-rw-r--r--net/ipv4/igmp.c2
-rw-r--r--net/ipv4/ip_fragment.c2
-rw-r--r--net/ipv4/ip_input.c2
-rw-r--r--net/ipv4/ipip.c2
-rw-r--r--net/ipv4/ipmr.c2
-rw-r--r--net/ipv4/route.c7
-rw-r--r--net/ipv4/sysctl_net_ipv4.c18
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv6/addrconf.c1
-rw-r--r--net/ipv6/af_inet6.c2
-rw-r--r--net/ipv6/ndisc.c11
-rw-r--r--net/netfilter/nf_conntrack_acct.c2
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/rfkill/rfkill-input.c1
-rw-r--r--net/sunrpc/clnt.c2
-rw-r--r--net/sunrpc/rpcb_clnt.c81
-rw-r--r--net/sunrpc/svc.c251
-rw-r--r--net/sunrpc/svc_xprt.c39
-rw-r--r--net/sunrpc/svcsock.c17
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_recvfrom.c187
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_sendto.c255
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c364
-rw-r--r--net/sunrpc/xprtsock.c4
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--scripts/bootgraph.pl147
-rwxr-xr-xscripts/checkpatch.pl388
-rw-r--r--scripts/mod/file2alias.c18
-rw-r--r--sound/aoa/soundbus/soundbus.h2
1069 files changed, 66233 insertions, 19559 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-regulator b/Documentation/ABI/testing/sysfs-class-regulator
index 79a4a75b2d2..3731f6f29bc 100644
--- a/Documentation/ABI/testing/sysfs-class-regulator
+++ b/Documentation/ABI/testing/sysfs-class-regulator
@@ -1,7 +1,7 @@
What: /sys/class/regulator/.../state
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
state. This holds the regulator output state.
@@ -27,7 +27,7 @@ Description:
What: /sys/class/regulator/.../type
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
type. This holds the regulator type.
@@ -51,7 +51,7 @@ Description:
What: /sys/class/regulator/.../microvolts
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
microvolts. This holds the regulator output voltage setting
@@ -65,7 +65,7 @@ Description:
What: /sys/class/regulator/.../microamps
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
microamps. This holds the regulator output current limit
@@ -79,7 +79,7 @@ Description:
What: /sys/class/regulator/.../opmode
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
opmode. This holds the regulator operating mode setting.
@@ -102,7 +102,7 @@ Description:
What: /sys/class/regulator/.../min_microvolts
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
min_microvolts. This holds the minimum safe working regulator
@@ -116,7 +116,7 @@ Description:
What: /sys/class/regulator/.../max_microvolts
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
max_microvolts. This holds the maximum safe working regulator
@@ -130,7 +130,7 @@ Description:
What: /sys/class/regulator/.../min_microamps
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
min_microamps. This holds the minimum safe working regulator
@@ -145,7 +145,7 @@ Description:
What: /sys/class/regulator/.../max_microamps
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
max_microamps. This holds the maximum safe working regulator
@@ -157,10 +157,23 @@ Description:
platform code.
+What: /sys/class/regulator/.../name
+Date: October 2008
+KernelVersion: 2.6.28
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
+Description:
+ Each regulator directory will contain a field called
+ name. This holds a string identifying the regulator for
+ display purposes.
+
+ NOTE: this will be empty if no suitable name is provided
+ by platform or regulator drivers.
+
+
What: /sys/class/regulator/.../num_users
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
num_users. This holds the number of consumer devices that
@@ -170,7 +183,7 @@ Description:
What: /sys/class/regulator/.../requested_microamps
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
requested_microamps. This holds the total requested load
@@ -181,7 +194,7 @@ Description:
What: /sys/class/regulator/.../parent
Date: April 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Some regulator directories will contain a link called parent.
This points to the parent or supply regulator if one exists.
@@ -189,7 +202,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_microvolts
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_microvolts. This holds the regulator output
@@ -203,7 +216,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_microvolts
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_microvolts. This holds the regulator output
@@ -217,7 +230,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_microvolts
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_microvolts. This holds the regulator output
@@ -231,7 +244,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_mode
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_mode. This holds the regulator operating mode
@@ -245,7 +258,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_mode
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_mode. This holds the regulator operating mode
@@ -258,7 +271,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_mode
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_mode. This holds the regulator operating mode
@@ -272,7 +285,7 @@ Description:
What: /sys/class/regulator/.../suspend_mem_state
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_mem_state. This holds the regulator operating state
@@ -287,7 +300,7 @@ Description:
What: /sys/class/regulator/.../suspend_disk_state
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_disk_state. This holds the regulator operating state
@@ -302,7 +315,7 @@ Description:
What: /sys/class/regulator/.../suspend_standby_state
Date: May 2008
KernelVersion: 2.6.26
-Contact: Liam Girdwood <lg@opensource.wolfsonmicro.com>
+Contact: Liam Girdwood <lrg@slimlogic.co.uk>
Description:
Each regulator directory will contain a field called
suspend_standby_state. This holds the regulator operating
diff --git a/Documentation/ABI/testing/sysfs-profiling b/Documentation/ABI/testing/sysfs-profiling
new file mode 100644
index 00000000000..b02d8b8c173
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-profiling
@@ -0,0 +1,13 @@
+What: /sys/kernel/profile
+Date: September 2008
+Contact: Dave Hansen <dave@linux.vnet.ibm.com>
+Description:
+ /sys/kernel/profile is the runtime equivalent
+ of the boot-time profile= option.
+
+ You can get the same effect running:
+
+ echo 2 > /sys/kernel/profile
+
+ as you would by issuing profile=2 on the boot
+ command line.
diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl
index 8a5dc6e021f..9eba4b7af73 100644
--- a/Documentation/DocBook/procfs-guide.tmpl
+++ b/Documentation/DocBook/procfs-guide.tmpl
@@ -14,17 +14,20 @@
<othername>(J.A.K.)</othername>
<surname>Mouw</surname>
<affiliation>
- <orgname>Delft University of Technology</orgname>
- <orgdiv>Faculty of Information Technology and Systems</orgdiv>
<address>
- <email>J.A.K.Mouw@its.tudelft.nl</email>
- <pob>PO BOX 5031</pob>
- <postcode>2600 GA</postcode>
- <city>Delft</city>
- <country>The Netherlands</country>
+ <email>mouw@nl.linux.org</email>
</address>
</affiliation>
</author>
+ <othercredit>
+ <contrib>
+ This software and documentation were written while working on the
+ LART computing board
+ (<ulink url="http://www.lartmaker.nl/">http://www.lartmaker.nl/</ulink>),
+ which was sponsored by the Delt University of Technology projects
+ Mobile Multi-media Communications and Ubiquitous Communications.
+ </contrib>
+ </othercredit>
</authorgroup>
<revhistory>
@@ -109,18 +112,6 @@
</para>
<para>
- This documentation was written while working on the LART
- computing board (<ulink
- url="http://www.lart.tudelft.nl/">http://www.lart.tudelft.nl/</ulink>),
- which is sponsored by the Mobile Multi-media Communications
- (<ulink
- url="http://www.mmc.tudelft.nl/">http://www.mmc.tudelft.nl/</ulink>)
- and Ubiquitous Communications (<ulink
- url="http://www.ubicom.tudelft.nl/">http://www.ubicom.tudelft.nl/</ulink>)
- projects.
- </para>
-
- <para>
Erik
</para>
</preface>
diff --git a/Documentation/DocBook/procfs_example.c b/Documentation/DocBook/procfs_example.c
index 2f3de0fb836..8c6396e4bf3 100644
--- a/Documentation/DocBook/procfs_example.c
+++ b/Documentation/DocBook/procfs_example.c
@@ -1,28 +1,16 @@
/*
* procfs_example.c: an example proc interface
*
- * Copyright (C) 2001, Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ * Copyright (C) 2001, Erik Mouw (mouw@nl.linux.org)
*
* This file accompanies the procfs-guide in the Linux kernel
* source. Its main use is to demonstrate the concepts and
* functions described in the guide.
*
* This software has been developed while working on the LART
- * computing board (http://www.lart.tudelft.nl/), which is
- * sponsored by the Mobile Multi-media Communications
- * (http://www.mmc.tudelft.nl/) and Ubiquitous Communications
- * (http://www.ubicom.tudelft.nl/) projects.
- *
- * The author can be reached at:
- *
- * Erik Mouw
- * Information and Communication Theory Group
- * Faculty of Information Technology and Systems
- * Delft University of Technology
- * P.O. Box 5031
- * 2600 GA Delft
- * The Netherlands
- *
+ * computing board (http://www.lartmaker.nl), which was sponsored
+ * by the Delt University of Technology projects Mobile Multi-media
+ * Communications and Ubiquitous Communications.
*
* This program is free software; you can redistribute
* it and/or modify it under the terms of the GNU General
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 48a3955f05f..8495fc97039 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -112,7 +112,7 @@ required reading:
Other excellent descriptions of how to create patches properly are:
"The Perfect Patch"
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
"Linux kernel patch submission format"
http://linux.yyz.us/patch-format.html
@@ -620,7 +620,7 @@ all time. It should describe the patch completely, containing:
For more details on what this should all look like, please see the
ChangeLog section of the document:
"The Perfect Patch"
- http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt
+ http://userweb.kernel.org/~akpm/stuff/tpp.txt
diff --git a/Documentation/SAK.txt b/Documentation/SAK.txt
index b9019ca872e..74be14679ed 100644
--- a/Documentation/SAK.txt
+++ b/Documentation/SAK.txt
@@ -1,5 +1,5 @@
Linux 2.4.2 Secure Attention Key (SAK) handling
-18 March 2001, Andrew Morton <akpm@osdl.org>
+18 March 2001, Andrew Morton
An operating system's Secure Attention Key is a security tool which is
provided as protection against trojan password capturing programs. It
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index 21f0795af20..ac5e0b2f109 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -85,3 +85,6 @@ kernel patches.
23: Tested after it has been merged into the -mm patchset to make sure
that it still works with all of the other queued patches and various
changes in the VM, VFS, and other subsystems.
+
+24: All memory barriers {e.g., barrier(), rmb(), wmb()} need a comment in the
+ source code that explains the logic of what they are doing and why.
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 24f2eb40cae..99e72a81fa2 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -41,7 +41,7 @@ Linux 2.4:
Linux 2.6:
The same rules apply as 2.4 except that you should follow linux-kernel
to track changes in API's. The final contact point for Linux 2.6
- submissions is Andrew Morton <akpm@osdl.org>.
+ submissions is Andrew Morton.
What Criteria Determine Acceptance
----------------------------------
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index f79ad9ff603..7b67f3bf8dd 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -77,7 +77,7 @@ Quilt:
http://savannah.nongnu.org/projects/quilt
Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/
+http://userweb.kernel.org/~akpm/stuff/patch-scripts.tar.gz
Instead of these scripts, quilt is the recommended patch management
tool (see above).
@@ -653,7 +653,7 @@ SECTION 3 - REFERENCES
----------------------
Andrew Morton, "The perfect patch" (tpp).
- <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+ <http://userweb.kernel.org/~akpm/stuff/tpp.txt>
Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
@@ -672,4 +672,9 @@ Kernel Documentation/CodingStyle:
Linus Torvalds's mail on the canonical patch format:
<http://lkml.org/lkml/2005/4/7/183>
+
+Andi Kleen, "On submitting kernel patches"
+ Some strategies to get difficult or controversal changes in.
+ http://halobates.de/on-submitting-patches.pdf
+
--
diff --git a/Documentation/cris/README b/Documentation/cris/README
index 795a1dabe6c..d9b086869a6 100644
--- a/Documentation/cris/README
+++ b/Documentation/cris/README
@@ -27,7 +27,7 @@ operating system.
The ETRAX 100LX chip
--------------------
-For reference, plase see the press-release:
+For reference, please see the press-release:
http://www.axis.com/news/us/001101_etrax.htm
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 27809357da5..1e89a51ea49 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -2,11 +2,13 @@
*.aux
*.bin
*.cpio
-*.css
+*.csp
+*.dsp
*.dvi
+*.elf
*.eps
-*.fw.gen.S
*.fw
+*.gen.S
*.gif
*.grep
*.grp
@@ -30,6 +32,7 @@
*.s
*.sgml
*.so
+*.so.dbg
*.symtypes
*.tab.c
*.tab.h
@@ -38,24 +41,17 @@
*.xml
*_MODULES
*_vga16.c
-*cscope*
*~
*.9
*.9.gz
.*
-.cscope
-.gitignore
-.mailmap
.mm
53c700_d.h
-53c8xx_d.h*
-COPYING
-CREDITS
CVS
ChangeSet
Image
Kerntypes
-MODS.txt
+Module.markers
Module.symvers
PENDING
SCCS
@@ -73,7 +69,9 @@ autoconf.h*
bbootsect
bin2c
binkernel.spec
+binoffset
bootsect
+bounds.h
bsetup
btfixupprep
build
@@ -89,39 +87,36 @@ config_data.h*
config_data.gz*
conmakehash
consolemap_deftbl.c*
+cpustr.h
crc32table.h*
cscope.*
-defkeymap.c*
+defkeymap.c
devlist.h*
docproc
-dummy_sym.c*
elf2ecoff
elfconfig.h*
-filelist
fixdep
fore200e_mkfirm
fore200e_pca_fw.c*
gconf
gen-devlist
-gen-kdb_cmds.c*
gen_crc32table
gen_init_cpio
genksyms
-gentbl
*_gray256.c
+ihex2fw
ikconfig.h*
initramfs_data.cpio
initramfs_data.cpio.gz
initramfs_list
kallsyms
kconfig
-kconfig.tk
-keywords.c*
+keywords.c
ksym.c*
ksym.h*
kxgettext
lkc_defs.h
-lex.c*
+lex.c
lex.*.c
logo_*.c
logo_*_clut224.c
@@ -130,7 +125,6 @@ lxdialog
mach-types
mach-types.h
machtypes.h
-make_times_h
map
maui_boot.h
mconf
@@ -138,6 +132,7 @@ miboot*
mk_elfconfig
mkboot
mkbugboot
+mkcpustr
mkdep
mkprep
mktables
@@ -145,11 +140,12 @@ mktree
modpost
modules.order
modversions.h*
+ncscope.*
offset.h
offsets.h
oui.c*
-parse.c*
-parse.h*
+parse.c
+parse.h
patches*
pca200e.bin
pca200e_ecd.bin2
@@ -157,7 +153,7 @@ piggy.gz
piggyback
pnmtologo
ppc_defs.h*
-promcon_tbl.c*
+promcon_tbl.c
pss_boot.h
qconf
raid6altivec*.c
@@ -168,27 +164,38 @@ series
setup
setup.bin
setup.elf
-sim710_d.h*
sImage
sm_tbl*
split-include
+syscalltab.h
tags
tftpboot.img
timeconst.h
times.h*
-tkparse
trix_boot.h
utsrelease.h*
+vdso-syms.lds
vdso.lds
+vdso32-int80-syms.lds
+vdso32-syms.lds
+vdso32-syscall-syms.lds
+vdso32-sysenter-syms.lds
+vdso32.lds
+vdso32.so.dbg
+vdso64.lds
+vdso64.so.dbg
version.h*
vmlinux
vmlinux-*
vmlinux.aout
-vmlinux*.lds*
-vmlinux*.scr
+vmlinux.lds
vsyscall.lds
+vsyscall_32.lds
wanxlfw.inc
uImage
unifdef
+wakeup.bin
+wakeup.elf
+wakeup.lds
zImage*
zconf.hash.c
diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
index 27a3160650a..dd9e944ea62 100644
--- a/Documentation/fb/intelfb.txt
+++ b/Documentation/fb/intelfb.txt
@@ -14,6 +14,7 @@ graphics devices. These would include:
Intel 915GM
Intel 945G
Intel 945GM
+ Intel 945GME
Intel 965G
Intel 965GM
diff --git a/Documentation/fb/uvesafb.txt b/Documentation/fb/uvesafb.txt
index bcfc233a008..7ac3c4078ff 100644
--- a/Documentation/fb/uvesafb.txt
+++ b/Documentation/fb/uvesafb.txt
@@ -52,7 +52,7 @@ are either given on the kernel command line or as module parameters, e.g.:
video=uvesafb:1024x768-32,mtrr:3,ywrap (compiled into the kernel)
- # modprobe uvesafb mode=1024x768-32 mtrr=3 scroll=ywrap (module)
+ # modprobe uvesafb mode_option=1024x768-32 mtrr=3 scroll=ywrap (module)
Accepted options:
@@ -105,7 +105,7 @@ vtotal:n
<mode> The mode you want to set, in the standard modedb format. Refer to
modedb.txt for a detailed description. When uvesafb is compiled as
a module, the mode string should be provided as a value of the
- 'mode' option.
+ 'mode_option' option.
vbemode:x
Force the use of VBE mode x. The mode will only be set if it's
diff --git a/Documentation/fb/viafb.modes b/Documentation/fb/viafb.modes
new file mode 100644
index 00000000000..02e5b487f00
--- /dev/null
+++ b/Documentation/fb/viafb.modes
@@ -0,0 +1,870 @@
+#
+#
+# These data are based on the CRTC parameters in
+#
+# VIA Integration Graphics Chip
+# (C) 2004 VIA Technologies Inc.
+#
+
+#
+# 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 640 480
+# Scan Frequency 31.469 kHz 59.94 Hz
+# Sync Width 3.813 us 0.064 ms
+# 12 chars 2 lines
+# Front Porch 0.636 us 0.318 ms
+# 2 chars 10 lines
+# Back Porch 1.907 us 1.048 ms
+# 6 chars 33 lines
+# Active Time 25.422 us 15.253 ms
+# 80 chars 480 lines
+# Blank Time 6.356 us 1.430 ms
+# 20 chars 45 lines
+# Polarity negative negative
+#
+
+mode "640x480-60"
+# D: 25.175 MHz, H: 31.469 kHz, V: 59.94 Hz
+ geometry 640 480 640 480 32
+ timings 39722 48 16 33 10 96 2 endmode mode "480x640-60"
+# D: 24.823 MHz, H: 39.780 kHz, V: 60.00 Hz
+ geometry 480 640 480 640 32 timings 39722 72 24 19 1 48 3 endmode
+#
+# 640x480, 75 Hz, Non-Interlaced (31.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 640 480
+# Scan Frequency 37.500 kHz 75.00 Hz
+# Sync Width 2.032 us 0.080 ms
+# 8 chars 3 lines
+# Front Porch 0.508 us 0.027 ms
+# 2 chars 1 lines
+# Back Porch 3.810 us 0.427 ms
+# 15 chars 16 lines
+# Active Time 20.317 us 12.800 ms
+# 80 chars 480 lines
+# Blank Time 6.349 us 0.533 ms
+# 25 chars 20 lines
+# Polarity negative negative
+#
+ mode "640x480-75"
+# D: 31.50 MHz, H: 37.500 kHz, V: 75.00 Hz
+ geometry 640 480 640 480 32 timings 31747 120 16 16 1 64 3 endmode
+#
+# 640x480, 85 Hz, Non-Interlaced (36.000 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 640 480
+# Scan Frequency 43.269 kHz 85.00 Hz
+# Sync Width 1.556 us 0.069 ms
+# 7 chars 3 lines
+# Front Porch 1.556 us 0.023 ms
+# 7 chars 1 lines
+# Back Porch 2.222 us 0.578 ms
+# 10 chars 25 lines
+# Active Time 17.778 us 11.093 ms
+# 80 chars 480 lines
+# Blank Time 5.333 us 0.670 ms
+# 24 chars 29 lines
+# Polarity negative negative
+#
+ mode "640x480-85"
+# D: 36.000 MHz, H: 43.269 kHz, V: 85.00 Hz
+ geometry 640 480 640 480 32 timings 27777 80 56 25 1 56 3 endmode
+#
+# 640x480, 100 Hz, Non-Interlaced (43.163 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 640 480
+# Scan Frequency 50.900 kHz 100.00 Hz
+# Sync Width 1.483 us 0.058 ms
+# 8 chars 3 lines
+# Front Porch 0.927 us 0.019 ms
+# 5 chars 1 lines
+# Back Porch 2.409 us 0.475 ms
+# 13 chars 25 lines
+# Active Time 14.827 us 9.430 ms
+# 80 chars 480 lines
+# Blank Time 4.819 us 0.570 ms
+# 26 chars 29 lines
+# Polarity positive positive
+#
+ mode "640x480-100"
+# D: 43.163 MHz, H: 50.900 kHz, V: 100.00 Hz
+ geometry 640 480 640 480 32 timings 23168 104 40 25 1 64 3 endmode
+#
+# 640x480, 120 Hz, Non-Interlaced (52.406 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 640 480
+# Scan Frequency 61.800 kHz 120.00 Hz
+# Sync Width 1.221 us 0.048 ms
+# 8 chars 3 lines
+# Front Porch 0.763 us 0.016 ms
+# 5 chars 1 lines
+# Back Porch 1.984 us 0.496 ms
+# 13 chars 31 lines
+# Active Time 12.212 us 7.767 ms
+# 80 chars 480 lines
+# Blank Time 3.969 us 0.566 ms
+# 26 chars 35 lines
+# Polarity positive positive
+#
+ mode "640x480-120"
+# D: 52.406 MHz, H: 61.800 kHz, V: 120.00 Hz
+ geometry 640 480 640 480 32 timings 19081 104 40 31 1 64 3 endmode
+#
+# 720x480, 60 Hz, Non-Interlaced (26.880 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 720 480
+# Scan Frequency 30.000 kHz 60.241 Hz
+# Sync Width 2.679 us 0.099 ms
+# 9 chars 3 lines
+# Front Porch 0.595 us 0.033 ms
+# 2 chars 1 lines
+# Back Porch 3.274 us 0.462 ms
+# 11 chars 14 lines
+# Active Time 26.786 us 16.000 ms
+# 90 chars 480 lines
+# Blank Time 6.548 us 0.600 ms
+# 22 chars 18 lines
+# Polarity positive positive
+#
+ mode "720x480-60"
+# D: 26.880 MHz, H: 30.000 kHz, V: 60.24 Hz
+ geometry 720 480 720 480 32 timings 37202 88 16 14 1 72 3 endmode
+#
+# 800x480, 60 Hz, Non-Interlaced (29.581 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 480
+# Scan Frequency 29.892 kHz 60.00 Hz
+# Sync Width 2.704 us 100.604 us
+# 10 chars 3 lines
+# Front Porch 0.541 us 33.535 us
+# 2 chars 1 lines
+# Back Porch 3.245 us 435.949 us
+# 12 chars 13 lines
+# Active Time 27.044 us 16.097 ms
+# 100 chars 480 lines
+# Blank Time 6.491 us 0.570 ms
+# 24 chars 17 lines
+# Polarity positive positive
+#
+ mode "800x480-60"
+# D: 29.500 MHz, H: 29.738 kHz, V: 60.00 Hz
+ geometry 800 480 800 480 32 timings 33805 96 24 10 3 72 7 endmode
+#
+# 720x576, 60 Hz, Non-Interlaced (32.668 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 720 576
+# Scan Frequency 35.820 kHz 60.00 Hz
+# Sync Width 2.204 us 0.083 ms
+# 9 chars 3 lines
+# Front Porch 0.735 us 0.027 ms
+# 3 chars 1 lines
+# Back Porch 2.939 us 0.459 ms
+# 12 chars 17 lines
+# Active Time 22.040 us 16.080 ms
+# 90 chars 476 lines
+# Blank Time 5.877 us 0.586 ms
+# 24 chars 21 lines
+# Polarity positive positive
+#
+ mode "720x576-60"
+# D: 32.668 MHz, H: 35.820 kHz, V: 60.00 Hz
+ geometry 720 576 720 576 32 timings 30611 96 24 17 1 72 3 endmode
+#
+# 800x600, 60 Hz, Non-Interlaced (40.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 600
+# Scan Frequency 37.879 kHz 60.32 Hz
+# Sync Width 3.200 us 0.106 ms
+# 16 chars 4 lines
+# Front Porch 1.000 us 0.026 ms
+# 5 chars 1 lines
+# Back Porch 2.200 us 0.607 ms
+# 11 chars 23 lines
+# Active Time 20.000 us 15.840 ms
+# 100 chars 600 lines
+# Blank Time 6.400 us 0.739 ms
+# 32 chars 28 lines
+# Polarity positive positive
+#
+ mode "800x600-60"
+# D: 40.00 MHz, H: 37.879 kHz, V: 60.32 Hz
+ geometry 800 600 800 600 32
+ timings 25000 88 40 23 1 128 4 hsync high vsync high endmode
+#
+# 800x600, 75 Hz, Non-Interlaced (49.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 600
+# Scan Frequency 46.875 kHz 75.00 Hz
+# Sync Width 1.616 us 0.064 ms
+# 10 chars 3 lines
+# Front Porch 0.323 us 0.021 ms
+# 2 chars 1 lines
+# Back Porch 3.232 us 0.448 ms
+# 20 chars 21 lines
+# Active Time 16.162 us 12.800 ms
+# 100 chars 600 lines
+# Blank Time 5.172 us 0.533 ms
+# 32 chars 25 lines
+# Polarity positive positive
+#
+ mode "800x600-75"
+# D: 49.50 MHz, H: 46.875 kHz, V: 75.00 Hz
+ geometry 800 600 800 600 32
+ timings 20203 160 16 21 1 80 3 hsync high vsync high endmode
+#
+# 800x600, 85 Hz, Non-Interlaced (56.25 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 600
+# Scan Frequency 53.674 kHz 85.061 Hz
+# Sync Width 1.138 us 0.056 ms
+# 8 chars 3 lines
+# Front Porch 0.569 us 0.019 ms
+# 4 chars 1 lines
+# Back Porch 2.702 us 0.503 ms
+# 19 chars 27 lines
+# Active Time 14.222 us 11.179 ms
+# 100 chars 600 lines
+# Blank Time 4.409 us 0.578 ms
+# 31 chars 31 lines
+# Polarity positive positive
+#
+ mode "800x600-85"
+# D: 56.25 MHz, H: 53.674 kHz, V: 85.061 Hz
+ geometry 800 600 800 600 32
+ timings 17777 152 32 27 1 64 3 hsync high vsync high endmode
+#
+# 800x600, 100 Hz, Non-Interlaced (67.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 600
+# Scan Frequency 62.500 kHz 100.00 Hz
+# Sync Width 0.948 us 0.064 ms
+# 8 chars 4 lines
+# Front Porch 0.000 us 0.112 ms
+# 0 chars 7 lines
+# Back Porch 3.200 us 0.224 ms
+# 27 chars 14 lines
+# Active Time 11.852 us 9.600 ms
+# 100 chars 600 lines
+# Blank Time 4.148 us 0.400 ms
+# 35 chars 25 lines
+# Polarity positive positive
+#
+ mode "800x600-100"
+# D: 67.50 MHz, H: 62.500 kHz, V: 100.00 Hz
+ geometry 800 600 800 600 32
+ timings 14667 216 0 14 7 64 4 hsync high vsync high endmode
+#
+# 800x600, 120 Hz, Non-Interlaced (83.950 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 800 600
+# Scan Frequency 77.160 kHz 120.00 Hz
+# Sync Width 1.048 us 0.039 ms
+# 11 chars 3 lines
+# Front Porch 0.667 us 0.013 ms
+# 7 chars 1 lines
+# Back Porch 1.715 us 0.507 ms
+# 18 chars 39 lines
+# Active Time 9.529 us 7.776 ms
+# 100 chars 600 lines
+# Blank Time 3.431 us 0.557 ms
+# 36 chars 43 lines
+# Polarity positive positive
+#
+ mode "800x600-120"
+# D: 83.950 MHz, H: 77.160 kHz, V: 120.00 Hz
+ geometry 800 600 800 600 32
+ timings 11912 144 56 39 1 88 3 hsync high vsync high endmode
+#
+# 848x480, 60 Hz, Non-Interlaced (31.490 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 848 480
+# Scan Frequency 29.820 kHz 60.00 Hz
+# Sync Width 2.795 us 0.099 ms
+# 11 chars 3 lines
+# Front Porch 0.508 us 0.033 ms
+# 2 chars 1 lines
+# Back Porch 3.303 us 0.429 ms
+# 13 chars 13 lines
+# Active Time 26.929 us 16.097 ms
+# 106 chars 480 lines
+# Blank Time 6.605 us 0.570 ms
+# 26 chars 17 lines
+# Polarity positive positive
+#
+ mode "848x480-60"
+# D: 31.500 MHz, H: 29.830 kHz, V: 60.00 Hz
+ geometry 848 480 848 480 32
+ timings 31746 104 24 12 3 80 5 hsync high vsync high endmode
+#
+# 856x480, 60 Hz, Non-Interlaced (31.728 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 856 480
+# Scan Frequency 29.820 kHz 60.00 Hz
+# Sync Width 2.774 us 0.099 ms
+# 11 chars 3 lines
+# Front Porch 0.504 us 0.033 ms
+# 2 chars 1 lines
+# Back Porch 3.728 us 0.429 ms
+# 13 chars 13 lines
+# Active Time 26.979 us 16.097 ms
+# 107 chars 480 lines
+# Blank Time 6.556 us 0.570 ms
+# 26 chars 17 lines
+# Polarity positive positive
+#
+ mode "856x480-60"
+# D: 31.728 MHz, H: 29.820 kHz, V: 60.00 Hz
+ geometry 856 480 856 480 32
+ timings 31518 104 16 13 1 88 3
+ hsync high vsync high endmode mode "960x600-60"
+# D: 45.250 MHz, H: 37.212 kHz, V: 60.00 Hz
+ geometry 960 600 960 600 32 timings 22099 128 32 15 3 96 6 endmode
+#
+# 1000x600, 60 Hz, Non-Interlaced (48.068 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1000 600
+# Scan Frequency 37.320 kHz 60.00 Hz
+# Sync Width 2.164 us 0.080 ms
+# 13 chars 3 lines
+# Front Porch 0.832 us 0.027 ms
+# 5 chars 1 lines
+# Back Porch 2.996 us 0.483 ms
+# 18 chars 18 lines
+# Active Time 20.804 us 16.077 ms
+# 125 chars 600 lines
+# Blank Time 5.991 us 0.589 ms
+# 36 chars 22 lines
+# Polarity negative positive
+#
+ mode "1000x600-60"
+# D: 48.068 MHz, H: 37.320 kHz, V: 60.00 Hz
+ geometry 1000 600 1000 600 32
+ timings 20834 144 40 18 1 104 3 endmode mode "1024x576-60"
+# D: 46.996 MHz, H: 35.820 kHz, V: 60.00 Hz
+ geometry 1024 576 1024 576 32
+ timings 21278 144 40 17 1 104 3 endmode mode "1024x600-60"
+# D: 48.964 MHz, H: 37.320 kHz, V: 60.00 Hz
+ geometry 1024 600 1024 600 32
+ timings 20461 144 40 18 1 104 3 endmode mode "1088x612-60"
+# D: 52.952 MHz, H: 38.040 kHz, V: 60.00 Hz
+ geometry 1088 612 1088 612 32 timings 18877 152 48 16 3 104 5 endmode
+#
+# 1024x512, 60 Hz, Non-Interlaced (41.291 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 512
+# Scan Frequency 31.860 kHz 60.00 Hz
+# Sync Width 2.519 us 0.094 ms
+# 13 chars 3 lines
+# Front Porch 0.775 us 0.031 ms
+# 4 chars 1 lines
+# Back Porch 3.294 us 0.465 ms
+# 17 chars 15 lines
+# Active Time 24.800 us 16.070 ms
+# 128 chars 512 lines
+# Blank Time 6.587 us 0.596 ms
+# 34 chars 19 lines
+# Polarity positive positive
+#
+ mode "1024x512-60"
+# D: 41.291 MHz, H: 31.860 kHz, V: 60.00 Hz
+ geometry 1024 512 1024 512 32
+ timings 24218 126 32 15 1 104 3 hsync high vsync high endmode
+#
+# 1024x600, 60 Hz, Non-Interlaced (48.875 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 768
+# Scan Frequency 37.252 kHz 60.00 Hz
+# Sync Width 2.128 us 80.532us
+# 13 chars 3 lines
+# Front Porch 0.818 us 26.844 us
+# 5 chars 1 lines
+# Back Porch 2.946 us 483.192 us
+# 18 chars 18 lines
+# Active Time 20.951 us 16.697 ms
+# 128 chars 622 lines
+# Blank Time 5.893 us 0.591 ms
+# 36 chars 22 lines
+# Polarity negative positive
+#
+#mode "1024x600-60"
+# # D: 48.875 MHz, H: 37.252 kHz, V: 60.00 Hz
+# geometry 1024 600 1024 600 32
+# timings 20460 144 40 18 1 104 3
+# endmode
+#
+# 1024x768, 60 Hz, Non-Interlaced (65.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 768
+# Scan Frequency 48.363 kHz 60.00 Hz
+# Sync Width 2.092 us 0.124 ms
+# 17 chars 6 lines
+# Front Porch 0.369 us 0.062 ms
+# 3 chars 3 lines
+# Back Porch 2.462 us 0.601 ms
+# 20 chars 29 lines
+# Active Time 15.754 us 15.880 ms
+# 128 chars 768 lines
+# Blank Time 4.923 us 0.786 ms
+# 40 chars 38 lines
+# Polarity negative negative
+#
+ mode "1024x768-60"
+# D: 65.00 MHz, H: 48.363 kHz, V: 60.00 Hz
+ geometry 1024 768 1024 768 32 timings 15385 160 24 29 3 136 6 endmode
+#
+# 1024x768, 75 Hz, Non-Interlaced (78.75 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 768
+# Scan Frequency 60.023 kHz 75.03 Hz
+# Sync Width 1.219 us 0.050 ms
+# 12 chars 3 lines
+# Front Porch 0.203 us 0.017 ms
+# 2 chars 1 lines
+# Back Porch 2.235 us 0.466 ms
+# 22 chars 28 lines
+# Active Time 13.003 us 12.795 ms
+# 128 chars 768 lines
+# Blank Time 3.657 us 0.533 ms
+# 36 chars 32 lines
+# Polarity positive positive
+#
+ mode "1024x768-75"
+# D: 78.75 MHz, H: 60.023 kHz, V: 75.03 Hz
+ geometry 1024 768 1024 768 32
+ timings 12699 176 16 28 1 96 3 hsync high vsync high endmode
+#
+# 1024x768, 85 Hz, Non-Interlaced (94.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 768
+# Scan Frequency 68.677 kHz 85.00 Hz
+# Sync Width 1.016 us 0.044 ms
+# 12 chars 3 lines
+# Front Porch 0.508 us 0.015 ms
+# 6 chars 1 lines
+# Back Porch 2.201 us 0.524 ms
+# 26 chars 36 lines
+# Active Time 10.836 us 11.183 ms
+# 128 chars 768 lines
+# Blank Time 3.725 us 0.582 ms
+# 44 chars 40 lines
+# Polarity positive positive
+#
+ mode "1024x768-85"
+# D: 94.50 MHz, H: 68.677 kHz, V: 85.00 Hz
+ geometry 1024 768 1024 768 32
+ timings 10582 208 48 36 1 96 3 hsync high vsync high endmode
+#
+# 1024x768, 100 Hz, Non-Interlaced (110.0 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1024 768
+# Scan Frequency 79.023 kHz 99.78 Hz
+# Sync Width 0.800 us 0.101 ms
+# 11 chars 8 lines
+# Front Porch 0.000 us 0.000 ms
+# 0 chars 0 lines
+# Back Porch 2.545 us 0.202 ms
+# 35 chars 16 lines
+# Active Time 9.309 us 9.719 ms
+# 128 chars 768 lines
+# Blank Time 3.345 us 0.304 ms
+# 46 chars 24 lines
+# Polarity negative negative
+#
+ mode "1024x768-100"
+# D: 113.3 MHz, H: 79.023 kHz, V: 99.78 Hz
+ geometry 1024 768 1024 768 32
+ timings 8825 280 0 16 0 88 8 endmode mode "1152x720-60"
+# D: 66.750 MHz, H: 44.859 kHz, V: 60.00 Hz
+ geometry 1152 720 1152 720 32 timings 14981 168 56 19 3 112 6 endmode
+#
+# 1152x864, 75 Hz, Non-Interlaced (110.0 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1152 864
+# Scan Frequency 75.137 kHz 74.99 Hz
+# Sync Width 1.309 us 0.106 ms
+# 18 chars 8 lines
+# Front Porch 0.245 us 0.599 ms
+# 3 chars 45 lines
+# Back Porch 1.282 us 1.132 ms
+# 18 chars 85 lines
+# Active Time 10.473 us 11.499 ms
+# 144 chars 864 lines
+# Blank Time 2.836 us 1.837 ms
+# 39 chars 138 lines
+# Polarity positive positive
+#
+ mode "1152x864-75"
+# D: 110.0 MHz, H: 75.137 kHz, V: 74.99 Hz
+ geometry 1152 864 1152 864 32
+ timings 9259 144 24 85 45 144 8
+ hsync high vsync high endmode mode "1200x720-60"
+# D: 70.184 MHz, H: 44.760 kHz, V: 60.00 Hz
+ geometry 1200 720 1200 720 32
+ timings 14253 184 28 22 1 128 3 endmode mode "1280x600-60"
+# D: 61.503 MHz, H: 37.320 kHz, V: 60.00 Hz
+ geometry 1280 600 1280 600 32
+ timings 16260 184 28 18 1 128 3 endmode mode "1280x720-50"
+# D: 60.466 MHz, H: 37.050 kHz, V: 50.00 Hz
+ geometry 1280 720 1280 720 32
+ timings 16538 176 48 17 1 128 3 endmode mode "1280x768-50"
+# D: 65.178 MHz, H: 39.550 kHz, V: 50.00 Hz
+ geometry 1280 768 1280 768 32 timings 15342 184 28 19 1 128 3 endmode
+#
+# 1280x768, 60 Hz, Non-Interlaced (80.136 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 768
+# Scan Frequency 47.700 kHz 60.00 Hz
+# Sync Width 1.697 us 0.063 ms
+# 17 chars 3 lines
+# Front Porch 0.799 us 0.021 ms
+# 8 chars 1 lines
+# Back Porch 2.496 us 0.483 ms
+# 25 chars 23 lines
+# Active Time 15.973 us 16.101 ms
+# 160 chars 768 lines
+# Blank Time 4.992 us 0.566 ms
+# 50 chars 27 lines
+# Polarity positive positive
+#
+ mode "1280x768-60"
+# D: 80.13 MHz, H: 47.700 kHz, V: 60.00 Hz
+ geometry 1280 768 1280 768 32
+ timings 12480 200 48 23 1 126 3 hsync high vsync high endmode
+#
+# 1280x800, 60 Hz, Non-Interlaced (83.375 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 800
+# Scan Frequency 49.628 kHz 60.00 Hz
+# Sync Width 1.631 us 60.450 us
+# 17 chars 3 lines
+# Front Porch 0.768 us 20.15 us
+# 8 chars 1 lines
+# Back Porch 2.399 us 0.483 ms
+# 25 chars 24 lines
+# Active Time 15.352 us 16.120 ms
+# 160 chars 800 lines
+# Blank Time 4.798 us 0.564 ms
+# 50 chars 28 lines
+# Polarity negtive positive
+#
+ mode "1280x800-60"
+# D: 83.500 MHz, H: 49.702 kHz, V: 60.00 Hz
+ geometry 1280 800 1280 800 32 timings 11994 200 72 22 3 128 6 endmode
+#
+# 1280x960, 60 Hz, Non-Interlaced (108.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 960
+# Scan Frequency 60.000 kHz 60.00 Hz
+# Sync Width 1.037 us 0.050 ms
+# 14 chars 3 lines
+# Front Porch 0.889 us 0.017 ms
+# 12 chars 1 lines
+# Back Porch 2.889 us 0.600 ms
+# 39 chars 36 lines
+# Active Time 11.852 us 16.000 ms
+# 160 chars 960 lines
+# Blank Time 4.815 us 0.667 ms
+# 65 chars 40 lines
+# Polarity positive positive
+#
+ mode "1280x960-60"
+# D: 108.00 MHz, H: 60.000 kHz, V: 60.00 Hz
+ geometry 1280 960 1280 960 32
+ timings 9259 312 96 36 1 112 3 hsync high vsync high endmode
+#
+# 1280x1024, 60 Hz, Non-Interlaced (108.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 1024
+# Scan Frequency 63.981 kHz 60.02 Hz
+# Sync Width 1.037 us 0.047 ms
+# 14 chars 3 lines
+# Front Porch 0.444 us 0.015 ms
+# 6 chars 1 lines
+# Back Porch 2.297 us 0.594 ms
+# 31 chars 38 lines
+# Active Time 11.852 us 16.005 ms
+# 160 chars 1024 lines
+# Blank Time 3.778 us 0.656 ms
+# 51 chars 42 lines
+# Polarity positive positive
+#
+ mode "1280x1024-60"
+# D: 108.00 MHz, H: 63.981 kHz, V: 60.02 Hz
+ geometry 1280 1024 1280 1024 32
+ timings 9260 248 48 38 1 112 3 hsync high vsync high endmode
+#
+# 1280x1024, 75 Hz, Non-Interlaced (135.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 1024
+# Scan Frequency 79.976 kHz 75.02 Hz
+# Sync Width 1.067 us 0.038 ms
+# 18 chars 3 lines
+# Front Porch 0.119 us 0.012 ms
+# 2 chars 1 lines
+# Back Porch 1.837 us 0.475 ms
+# 31 chars 38 lines
+# Active Time 9.481 us 12.804 ms
+# 160 chars 1024 lines
+# Blank Time 3.022 us 0.525 ms
+# 51 chars 42 lines
+# Polarity positive positive
+#
+ mode "1280x1024-75"
+# D: 135.00 MHz, H: 79.976 kHz, V: 75.02 Hz
+ geometry 1280 1024 1280 1024 32
+ timings 7408 248 16 38 1 144 3 hsync high vsync high endmode
+#
+# 1280x1024, 85 Hz, Non-Interlaced (157.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 1024
+# Scan Frequency 91.146 kHz 85.02 Hz
+# Sync Width 1.016 us 0.033 ms
+# 20 chars 3 lines
+# Front Porch 0.406 us 0.011 ms
+# 8 chars 1 lines
+# Back Porch 1.422 us 0.483 ms
+# 28 chars 44 lines
+# Active Time 8.127 us 11.235 ms
+# 160 chars 1024 lines
+# Blank Time 2.844 us 0.527 ms
+# 56 chars 48 lines
+# Polarity positive positive
+#
+ mode "1280x1024-85"
+# D: 157.50 MHz, H: 91.146 kHz, V: 85.02 Hz
+ geometry 1280 1024 1280 1024 32
+ timings 6349 224 64 44 1 160 3
+ hsync high vsync high endmode mode "1440x900-60"
+# D: 106.500 MHz, H: 55.935 kHz, V: 60.00 Hz
+ geometry 1440 900 1440 900 32
+ timings 9390 232 80 25 3 152 6
+ hsync high vsync high endmode mode "1440x900-75"
+# D: 136.750 MHz, H: 70.635 kHz, V: 75.00 Hz
+ geometry 1440 900 1440 900 32
+ timings 7315 248 96 33 3 152 6 hsync high vsync high endmode
+#
+# 1440x1050, 60 Hz, Non-Interlaced (125.10 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1440 1050
+# Scan Frequency 65.220 kHz 60.00 Hz
+# Sync Width 1.204 us 0.046 ms
+# 19 chars 3 lines
+# Front Porch 0.760 us 0.015 ms
+# 12 chars 1 lines
+# Back Porch 1.964 us 0.495 ms
+# 31 chars 33 lines
+# Active Time 11.405 us 16.099 ms
+# 180 chars 1050 lines
+# Blank Time 3.928 us 0.567 ms
+# 62 chars 37 lines
+# Polarity positive positive
+#
+ mode "1440x1050-60"
+# D: 125.10 MHz, H: 65.220 kHz, V: 60.00 Hz
+ geometry 1440 1050 1440 1050 32
+ timings 7993 248 96 33 1 152 3
+ hsync high vsync high endmode mode "1600x900-60"
+# D: 118.250 MHz, H: 55.990 kHz, V: 60.00 Hz
+ geometry 1600 900 1600 900 32
+ timings 8415 256 88 26 3 168 5 endmode mode "1600x1024-60"
+# D: 136.358 MHz, H: 63.600 kHz, V: 60.00 Hz
+ geometry 1600 1024 1600 1024 32 timings 7315 272 104 32 1 168 3 endmode
+#
+# 1600x1200, 60 Hz, Non-Interlaced (156.00 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1600 1200
+# Scan Frequency 76.200 kHz 60.00 Hz
+# Sync Width 1.026 us 0.105 ms
+# 20 chars 8 lines
+# Front Porch 0.205 us 0.131 ms
+# 4 chars 10 lines
+# Back Porch 1.636 us 0.682 ms
+# 32 chars 52 lines
+# Active Time 10.256 us 15.748 ms
+# 200 chars 1200 lines
+# Blank Time 2.872 us 0.866 ms
+# 56 chars 66 lines
+# Polarity negative negative
+#
+ mode "1600x1200-60"
+# D: 156.00 MHz, H: 76.200 kHz, V: 60.00 Hz
+ geometry 1600 1200 1600 1200 32 timings 6172 256 32 52 10 160 8 endmode
+#
+# 1600x1200, 75 Hz, Non-Interlaced (202.50 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1600 1200
+# Scan Frequency 93.750 kHz 75.00 Hz
+# Sync Width 0.948 us 0.032 ms
+# 24 chars 3 lines
+# Front Porch 0.316 us 0.011 ms
+# 8 chars 1 lines
+# Back Porch 1.501 us 0.491 ms
+# 38 chars 46 lines
+# Active Time 7.901 us 12.800 ms
+# 200 chars 1200 lines
+# Blank Time 2.765 us 0.533 ms
+# 70 chars 50 lines
+# Polarity positive positive
+#
+ mode "1600x1200-75"
+# D: 202.50 MHz, H: 93.750 kHz, V: 75.00 Hz
+ geometry 1600 1200 1600 1200 32
+ timings 4938 304 64 46 1 192 3
+ hsync high vsync high endmode mode "1680x1050-60"
+# D: 146.250 MHz, H: 65.290 kHz, V: 59.954 Hz
+ geometry 1680 1050 1680 1050 32
+ timings 6814 280 104 30 3 176 6
+ hsync high vsync high endmode mode "1680x1050-75"
+# D: 187.000 MHz, H: 82.306 kHz, V: 74.892 Hz
+ geometry 1680 1050 1680 1050 32
+ timings 5348 296 120 40 3 176 6
+ hsync high vsync high endmode mode "1792x1344-60"
+# D: 202.975 MHz, H: 83.460 kHz, V: 60.00 Hz
+ geometry 1792 1344 1792 1344 32
+ timings 4902 320 128 43 1 192 3
+ hsync high vsync high endmode mode "1856x1392-60"
+# D: 218.571 MHz, H: 86.460 kHz, V: 60.00 Hz
+ geometry 1856 1392 1856 1392 32
+ timings 4577 336 136 45 1 200 3
+ hsync high vsync high endmode mode "1920x1200-60"
+# D: 193.250 MHz, H: 74.556 kHz, V: 60.00 Hz
+ geometry 1920 1200 1920 1200 32
+ timings 5173 336 136 36 3 200 6
+ hsync high vsync high endmode mode "1920x1440-60"
+# D: 234.000 MHz, H:90.000 kHz, V: 60.00 Hz
+ geometry 1920 1440 1920 1440 32
+ timings 4274 344 128 56 1 208 3
+ hsync high vsync high endmode mode "1920x1440-75"
+# D: 297.000 MHz, H:112.500 kHz, V: 75.00 Hz
+ geometry 1920 1440 1920 1440 32
+ timings 3367 352 144 56 1 224 3
+ hsync high vsync high endmode mode "2048x1536-60"
+# D: 267.250 MHz, H: 95.446 kHz, V: 60.00 Hz
+ geometry 2048 1536 2048 1536 32
+ timings 3742 376 152 49 3 224 4 hsync high vsync high endmode
+#
+# 1280x720, 60 Hz, Non-Interlaced (74.481 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1280 720
+# Scan Frequency 44.760 kHz 60.00 Hz
+# Sync Width 1.826 us 67.024 ms
+# 17 chars 3 lines
+# Front Porch 0.752 us 22.341 ms
+# 7 chars 1 lines
+# Back Porch 2.578 us 491.510 ms
+# 24 chars 22 lines
+# Active Time 17.186 us 16.086 ms
+# 160 chars 720 lines
+# Blank Time 5.156 us 0.581 ms
+# 48 chars 26 lines
+# Polarity negative negative
+#
+ mode "1280x720-60"
+# D: 74.481 MHz, H: 44.760 kHz, V: 60.00 Hz
+ geometry 1280 720 1280 720 32 timings 13426 192 64 22 1 136 3 endmode
+#
+# 1920x1080, 60 Hz, Non-Interlaced (172.798 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1920 1080
+# Scan Frequency 67.080 kHz 60.00 Hz
+# Sync Width 1.204 us 44.723 ms
+# 26 chars 3 lines
+# Front Porch 0.694 us 14.908 ms
+# 15 chars 1 lines
+# Back Porch 1.898 us 506.857 ms
+# 41 chars 34 lines
+# Active Time 11.111 us 16.100 ms
+# 240 chars 1080 lines
+# Blank Time 3.796 us 0.566 ms
+# 82 chars 38 lines
+# Polarity negative negative
+#
+ mode "1920x1080-60"
+# D: 74.481 MHz, H: 67.080 kHz, V: 60.00 Hz
+ geometry 1920 1080 1920 1080 32 timings 5787 328 120 34 1 208 3 endmode
+#
+# 1400x1050, 60 Hz, Non-Interlaced (122.61 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1400 1050
+# Scan Frequency 65.218 kHz 59.99 Hz
+# Sync Width 1.037 us 0.047 ms
+# 19 chars 3 lines
+# Front Porch 0.444 us 0.015 ms
+# 11 chars 1 lines
+# Back Porch 1.185 us 0.188 ms
+# 30 chars 33 lines
+# Active Time 12.963 us 16.411 ms
+# 175 chars 1050 lines
+# Blank Time 2.667 us 0.250 ms
+# 60 chars 37 lines
+# Polarity negative positive
+#
+ mode "1400x1050-60"
+# D: 122.750 MHz, H: 65.317 kHz, V: 59.99 Hz
+ geometry 1400 1050 1408 1050 32
+ timings 8214 232 88 32 3 144 4 endmode mode "1400x1050-75"
+# D: 156.000 MHz, H: 82.278 kHz, V: 74.867 Hz
+ geometry 1400 1050 1408 1050 32 timings 6410 248 104 42 3 144 4 endmode
+#
+# 1366x768, 60 Hz, Non-Interlaced (85.86 MHz dotclock)
+#
+# Horizontal Vertical
+# Resolution 1366 768
+# Scan Frequency 47.700 kHz 60.00 Hz
+# Sync Width 1.677 us 0.063 ms
+# 18 chars 3 lines
+# Front Porch 0.839 us 0.021 ms
+# 9 chars 1 lines
+# Back Porch 2.516 us 0.482 ms
+# 27 chars 23 lines
+# Active Time 15.933 us 16.101 ms
+# 171 chars 768 lines
+# Blank Time 5.031 us 0.566 ms
+# 54 chars 27 lines
+# Polarity negative positive
+#
+ mode "1360x768-60"
+# D: 84.750 MHz, H: 47.720 kHz, V: 60.00 Hz
+ geometry 1360 768 1360 768 32
+ timings 11799 208 72 22 3 136 5 endmode mode "1366x768-60"
+# D: 85.86 MHz, H: 47.700 kHz, V: 60.00 Hz
+ geometry 1366 768 1366 768 32
+ timings 11647 216 72 23 1 144 3 endmode mode "1366x768-50"
+# D: 69,924 MHz, H: 39.550 kHz, V: 50.00 Hz
+ geometry 1366 768 1366 768 32 timings 14301 200 56 19 1 144 3 endmode
diff --git a/Documentation/fb/viafb.txt b/Documentation/fb/viafb.txt
new file mode 100644
index 00000000000..67dbf442b0b
--- /dev/null
+++ b/Documentation/fb/viafb.txt
@@ -0,0 +1,214 @@
+
+ VIA Integration Graphic Chip Console Framebuffer Driver
+
+[Platform]
+-----------------------
+ The console framebuffer driver is for graphics chips of
+ VIA UniChrome Family(CLE266, PM800 / CN400 / CN300,
+ P4M800CE / P4M800Pro / CN700 / VN800,
+ CX700 / VX700, K8M890, P4M890,
+ CN896 / P4M900, VX800)
+
+[Driver features]
+------------------------
+ Device: CRT, LCD, DVI
+
+ Support viafb_mode:
+ CRT:
+ 640x480(60, 75, 85, 100, 120 Hz), 720x480(60 Hz),
+ 720x576(60 Hz), 800x600(60, 75, 85, 100, 120 Hz),
+ 848x480(60 Hz), 856x480(60 Hz), 1024x512(60 Hz),
+ 1024x768(60, 75, 85, 100 Hz), 1152x864(75 Hz),
+ 1280x768(60 Hz), 1280x960(60 Hz), 1280x1024(60, 75, 85 Hz),
+ 1440x1050(60 Hz), 1600x1200(60, 75 Hz), 1280x720(60 Hz),
+ 1920x1080(60 Hz), 1400x1050(60 Hz), 800x480(60 Hz)
+
+ color depth: 8 bpp, 16 bpp, 32 bpp supports.
+
+ Support 2D hardware accelerator.
+
+[Using the viafb module]
+-- -- --------------------
+ Start viafb with default settings:
+ #modprobe viafb
+
+ Start viafb with with user options:
+ #modprobe viafb viafb_mode=800x600 viafb_bpp=16 viafb_refresh=60
+ viafb_active_dev=CRT+DVI viafb_dvi_port=DVP1
+ viafb_mode1=1024x768 viafb_bpp=16 viafb_refresh1=60
+ viafb_SAMM_ON=1
+
+ viafb_mode:
+ 640x480 (default)
+ 720x480
+ 800x600
+ 1024x768
+ ......
+
+ viafb_bpp:
+ 8, 16, 32 (default:32)
+
+ viafb_refresh:
+ 60, 75, 85, 100, 120 (default:60)
+
+ viafb_lcd_dsp_method:
+ 0 : expansion (default)
+ 1 : centering
+
+ viafb_lcd_mode:
+ 0 : LCD panel with LSB data format input (default)
+ 1 : LCD panel with MSB data format input
+
+ viafb_lcd_panel_id:
+ 0 : Resolution: 640x480, Channel: single, Dithering: Enable
+ 1 : Resolution: 800x600, Channel: single, Dithering: Enable
+ 2 : Resolution: 1024x768, Channel: single, Dithering: Enable (default)
+ 3 : Resolution: 1280x768, Channel: single, Dithering: Enable
+ 4 : Resolution: 1280x1024, Channel: dual, Dithering: Enable
+ 5 : Resolution: 1400x1050, Channel: dual, Dithering: Enable
+ 6 : Resolution: 1600x1200, Channel: dual, Dithering: Enable
+
+ 8 : Resolution: 800x480, Channel: single, Dithering: Enable
+ 9 : Resolution: 1024x768, Channel: dual, Dithering: Enable
+ 10: Resolution: 1024x768, Channel: single, Dithering: Disable
+ 11: Resolution: 1024x768, Channel: dual, Dithering: Disable
+ 12: Resolution: 1280x768, Channel: single, Dithering: Disable
+ 13: Resolution: 1280x1024, Channel: dual, Dithering: Disable
+ 14: Resolution: 1400x1050, Channel: dual, Dithering: Disable
+ 15: Resolution: 1600x1200, Channel: dual, Dithering: Disable
+ 16: Resolution: 1366x768, Channel: single, Dithering: Disable
+ 17: Resolution: 1024x600, Channel: single, Dithering: Enable
+ 18: Resolution: 1280x768, Channel: dual, Dithering: Enable
+ 19: Resolution: 1280x800, Channel: single, Dithering: Enable
+
+ viafb_accel:
+ 0 : No 2D Hardware Acceleration
+ 1 : 2D Hardware Acceleration (default)
+
+ viafb_SAMM_ON:
+ 0 : viafb_SAMM_ON disable (default)
+ 1 : viafb_SAMM_ON enable
+
+ viafb_mode1: (secondary display device)
+ 640x480 (default)
+ 720x480
+ 800x600
+ 1024x768
+ ... ...
+
+ viafb_bpp1: (secondary display device)
+ 8, 16, 32 (default:32)
+
+ viafb_refresh1: (secondary display device)
+ 60, 75, 85, 100, 120 (default:60)
+
+ viafb_active_dev:
+ This option is used to specify active devices.(CRT, DVI, CRT+LCD...)
+ DVI stands for DVI or HDMI, E.g., If you want to enable HDMI,
+ set viafb_active_dev=DVI. In SAMM case, the previous of
+ viafb_active_dev is primary device, and the following is
+ secondary device.
+
+ For example:
+ To enable one device, such as DVI only, we can use:
+ modprobe viafb viafb_active_dev=DVI
+ To enable two devices, such as CRT+DVI:
+ modprobe viafb viafb_active_dev=CRT+DVI;
+
+ For DuoView case, we can use:
+ modprobe viafb viafb_active_dev=CRT+DVI
+ OR
+ modprobe viafb viafb_active_dev=DVI+CRT...
+
+ For SAMM case:
+ If CRT is primary and DVI is secondary, we should use:
+ modprobe viafb viafb_active_dev=CRT+DVI viafb_SAMM_ON=1...
+ If DVI is primary and CRT is secondary, we should use:
+ modprobe viafb viafb_active_dev=DVI+CRT viafb_SAMM_ON=1...
+
+ viafb_display_hardware_layout:
+ This option is used to specify display hardware layout for CX700 chip.
+ 1 : LCD only
+ 2 : DVI only
+ 3 : LCD+DVI (default)
+ 4 : LCD1+LCD2 (internal + internal)
+ 16: LCD1+ExternalLCD2 (internal + external)
+
+ viafb_second_size:
+ This option is used to set second device memory size(MB) in SAMM case.
+ The minimal size is 16.
+
+ viafb_platform_epia_dvi:
+ This option is used to enable DVI on EPIA - M
+ 0 : No DVI on EPIA - M (default)
+ 1 : DVI on EPIA - M
+
+ viafb_bus_width:
+ When using 24 - Bit Bus Width Digital Interface,
+ this option should be set.
+ 12: 12-Bit LVDS or 12-Bit TMDS (default)
+ 24: 24-Bit LVDS or 24-Bit TMDS
+
+ viafb_device_lcd_dualedge:
+ When using Dual Edge Panel, this option should be set.
+ 0 : No Dual Edge Panel (default)
+ 1 : Dual Edge Panel
+
+ viafb_video_dev:
+ This option is used to specify video output devices(CRT, DVI, LCD) for
+ duoview case.
+ For example:
+ To output video on DVI, we should use:
+ modprobe viafb viafb_video_dev=DVI...
+
+ viafb_lcd_port:
+ This option is used to specify LCD output port,
+ available values are "DVP0" "DVP1" "DFP_HIGHLOW" "DFP_HIGH" "DFP_LOW".
+ for external LCD + external DVI on CX700(External LCD is on DVP0),
+ we should use:
+ modprobe viafb viafb_lcd_port=DVP0...
+
+Notes:
+ 1. CRT may not display properly for DuoView CRT & DVI display at
+ the "640x480" PAL mode with DVI overscan enabled.
+ 2. SAMM stands for single adapter multi monitors. It is different from
+ multi-head since SAMM support multi monitor at driver layers, thus fbcon
+ layer doesn't even know about it; SAMM's second screen doesn't have a
+ device node file, thus a user mode application can't access it directly.
+ When SAMM is enabled, viafb_mode and viafb_mode1, viafb_bpp and
+ viafb_bpp1, viafb_refresh and viafb_refresh1 can be different.
+ 3. When console is depending on viafbinfo1, dynamically change resolution
+ and bpp, need to call VIAFB specified ioctl interface VIAFB_SET_DEVICE
+ instead of calling common ioctl function FBIOPUT_VSCREENINFO since
+ viafb doesn't support multi-head well, or it will cause screen crush.
+ 4. VX800 2D accelerator hasn't been supported in this driver yet. When
+ using driver on VX800, the driver will disable the acceleration
+ function as default.
+
+
+[Configure viafb with "fbset" tool]
+-----------------------------------
+ "fbset" is an inbox utility of Linux.
+ 1. Inquire current viafb information, type,
+ # fbset -i
+
+ 2. Set various resolutions and viafb_refresh rates,
+ # fbset <resolution-vertical_sync>
+
+ example,
+ # fbset "1024x768-75"
+ or
+ # fbset -g 1024 768 1024 768 32
+ Check the file "/etc/fb.modes" to find display modes available.
+
+ 3. Set the color depth,
+ # fbset -depth <value>
+
+ example,
+ # fbset -depth 16
+
+[Bootup with viafb]:
+--------------------
+ Add the following line to your grub.conf:
+ append = "video=viafb:viafb_mode=1024x768,viafb_bpp=32,viafb_refresh=85"
+
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index cc8093c15cf..f5f812daf9f 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -287,6 +287,22 @@ Who: Glauber Costa <gcosta@redhat.com>
---------------------------
+What: remove HID compat support
+When: 2.6.29
+Why: needed only as a temporary solution until distros fix themselves up
+Who: Jiri Slaby <jirislaby@gmail.com>
+
+---------------------------
+
+What: print_fn_descriptor_symbol()
+When: October 2009
+Why: The %pF vsprintf format provides the same functionality in a
+ simpler way. print_fn_descriptor_symbol() is deprecated but
+ still present to give out-of-tree modules time to change.
+Who: Bjorn Helgaas <bjorn.helgaas@hp.com>
+
+---------------------------
+
What: /sys/o2cb symlink
When: January 2010
Why: /sys/fs/o2cb is the proper location for this information - /sys/o2cb
diff --git a/Documentation/filesystems/autofs4-mount-control.txt b/Documentation/filesystems/autofs4-mount-control.txt
new file mode 100644
index 00000000000..c6341745df3
--- /dev/null
+++ b/Documentation/filesystems/autofs4-mount-control.txt
@@ -0,0 +1,393 @@
+
+Miscellaneous Device control operations for the autofs4 kernel module
+====================================================================
+
+The problem
+===========
+
+There is a problem with active restarts in autofs (that is to say
+restarting autofs when there are busy mounts).
+
+During normal operation autofs uses a file descriptor opened on the
+directory that is being managed in order to be able to issue control
+operations. Using a file descriptor gives ioctl operations access to
+autofs specific information stored in the super block. The operations
+are things such as setting an autofs mount catatonic, setting the
+expire timeout and requesting expire checks. As is explained below,
+certain types of autofs triggered mounts can end up covering an autofs
+mount itself which prevents us being able to use open(2) to obtain a
+file descriptor for these operations if we don't already have one open.
+
+Currently autofs uses "umount -l" (lazy umount) to clear active mounts
+at restart. While using lazy umount works for most cases, anything that
+needs to walk back up the mount tree to construct a path, such as
+getcwd(2) and the proc file system /proc/<pid>/cwd, no longer works
+because the point from which the path is constructed has been detached
+from the mount tree.
+
+The actual problem with autofs is that it can't reconnect to existing
+mounts. Immediately one thinks of just adding the ability to remount
+autofs file systems would solve it, but alas, that can't work. This is
+because autofs direct mounts and the implementation of "on demand mount
+and expire" of nested mount trees have the file system mounted directly
+on top of the mount trigger directory dentry.
+
+For example, there are two types of automount maps, direct (in the kernel
+module source you will see a third type called an offset, which is just
+a direct mount in disguise) and indirect.
+
+Here is a master map with direct and indirect map entries:
+
+/- /etc/auto.direct
+/test /etc/auto.indirect
+
+and the corresponding map files:
+
+/etc/auto.direct:
+
+/automount/dparse/g6 budgie:/autofs/export1
+/automount/dparse/g1 shark:/autofs/export1
+and so on.
+
+/etc/auto.indirect:
+
+g1 shark:/autofs/export1
+g6 budgie:/autofs/export1
+and so on.
+
+For the above indirect map an autofs file system is mounted on /test and
+mounts are triggered for each sub-directory key by the inode lookup
+operation. So we see a mount of shark:/autofs/export1 on /test/g1, for
+example.
+
+The way that direct mounts are handled is by making an autofs mount on
+each full path, such as /automount/dparse/g1, and using it as a mount
+trigger. So when we walk on the path we mount shark:/autofs/export1 "on
+top of this mount point". Since these are always directories we can
+use the follow_link inode operation to trigger the mount.
+
+But, each entry in direct and indirect maps can have offsets (making
+them multi-mount map entries).
+
+For example, an indirect mount map entry could also be:
+
+g1 \
+ / shark:/autofs/export5/testing/test \
+ /s1 shark:/autofs/export/testing/test/s1 \
+ /s2 shark:/autofs/export5/testing/test/s2 \
+ /s1/ss1 shark:/autofs/export1 \
+ /s2/ss2 shark:/autofs/export2
+
+and a similarly a direct mount map entry could also be:
+
+/automount/dparse/g1 \
+ / shark:/autofs/export5/testing/test \
+ /s1 shark:/autofs/export/testing/test/s1 \
+ /s2 shark:/autofs/export5/testing/test/s2 \
+ /s1/ss1 shark:/autofs/export2 \
+ /s2/ss2 shark:/autofs/export2
+
+One of the issues with version 4 of autofs was that, when mounting an
+entry with a large number of offsets, possibly with nesting, we needed
+to mount and umount all of the offsets as a single unit. Not really a
+problem, except for people with a large number of offsets in map entries.
+This mechanism is used for the well known "hosts" map and we have seen
+cases (in 2.4) where the available number of mounts are exhausted or
+where the number of privileged ports available is exhausted.
+
+In version 5 we mount only as we go down the tree of offsets and
+similarly for expiring them which resolves the above problem. There is
+somewhat more detail to the implementation but it isn't needed for the
+sake of the problem explanation. The one important detail is that these
+offsets are implemented using the same mechanism as the direct mounts
+above and so the mount points can be covered by a mount.
+
+The current autofs implementation uses an ioctl file descriptor opened
+on the mount point for control operations. The references held by the
+descriptor are accounted for in checks made to determine if a mount is
+in use and is also used to access autofs file system information held
+in the mount super block. So the use of a file handle needs to be
+retained.
+
+
+The Solution
+============
+
+To be able to restart autofs leaving existing direct, indirect and
+offset mounts in place we need to be able to obtain a file handle
+for these potentially covered autofs mount points. Rather than just
+implement an isolated operation it was decided to re-implement the
+existing ioctl interface and add new operations to provide this
+functionality.
+
+In addition, to be able to reconstruct a mount tree that has busy mounts,
+the uid and gid of the last user that triggered the mount needs to be
+available because these can be used as macro substitution variables in
+autofs maps. They are recorded at mount request time and an operation
+has been added to retrieve them.
+
+Since we're re-implementing the control interface, a couple of other
+problems with the existing interface have been addressed. First, when
+a mount or expire operation completes a status is returned to the
+kernel by either a "send ready" or a "send fail" operation. The
+"send fail" operation of the ioctl interface could only ever send
+ENOENT so the re-implementation allows user space to send an actual
+status. Another expensive operation in user space, for those using
+very large maps, is discovering if a mount is present. Usually this
+involves scanning /proc/mounts and since it needs to be done quite
+often it can introduce significant overhead when there are many entries
+in the mount table. An operation to lookup the mount status of a mount
+point dentry (covered or not) has also been added.
+
+Current kernel development policy recommends avoiding the use of the
+ioctl mechanism in favor of systems such as Netlink. An implementation
+using this system was attempted to evaluate its suitability and it was
+found to be inadequate, in this case. The Generic Netlink system was
+used for this as raw Netlink would lead to a significant increase in
+complexity. There's no question that the Generic Netlink system is an
+elegant solution for common case ioctl functions but it's not a complete
+replacement probably because it's primary purpose in life is to be a
+message bus implementation rather than specifically an ioctl replacement.
+While it would be possible to work around this there is one concern
+that lead to the decision to not use it. This is that the autofs
+expire in the daemon has become far to complex because umount
+candidates are enumerated, almost for no other reason than to "count"
+the number of times to call the expire ioctl. This involves scanning
+the mount table which has proved to be a big overhead for users with
+large maps. The best way to improve this is try and get back to the
+way the expire was done long ago. That is, when an expire request is
+issued for a mount (file handle) we should continually call back to
+the daemon until we can't umount any more mounts, then return the
+appropriate status to the daemon. At the moment we just expire one
+mount at a time. A Generic Netlink implementation would exclude this
+possibility for future development due to the requirements of the
+message bus architecture.
+
+
+autofs4 Miscellaneous Device mount control interface
+====================================================
+
+The control interface is opening a device node, typically /dev/autofs.
+
+All the ioctls use a common structure to pass the needed parameter
+information and return operation results:
+
+struct autofs_dev_ioctl {
+ __u32 ver_major;
+ __u32 ver_minor;
+ __u32 size; /* total size of data passed in
+ * including this struct */
+ __s32 ioctlfd; /* automount command fd */
+
+ __u32 arg1; /* Command parameters */
+ __u32 arg2;
+
+ char path[0];
+};
+
+The ioctlfd field is a mount point file descriptor of an autofs mount
+point. It is returned by the open call and is used by all calls except
+the check for whether a given path is a mount point, where it may
+optionally be used to check a specific mount corresponding to a given
+mount point file descriptor, and when requesting the uid and gid of the
+last successful mount on a directory within the autofs file system.
+
+The fields arg1 and arg2 are used to communicate parameters and results of
+calls made as described below.
+
+The path field is used to pass a path where it is needed and the size field
+is used account for the increased structure length when translating the
+structure sent from user space.
+
+This structure can be initialized before setting specific fields by using
+the void function call init_autofs_dev_ioctl(struct autofs_dev_ioctl *).
+
+All of the ioctls perform a copy of this structure from user space to
+kernel space and return -EINVAL if the size parameter is smaller than
+the structure size itself, -ENOMEM if the kernel memory allocation fails
+or -EFAULT if the copy itself fails. Other checks include a version check
+of the compiled in user space version against the module version and a
+mismatch results in a -EINVAL return. If the size field is greater than
+the structure size then a path is assumed to be present and is checked to
+ensure it begins with a "/" and is NULL terminated, otherwise -EINVAL is
+returned. Following these checks, for all ioctl commands except
+AUTOFS_DEV_IOCTL_VERSION_CMD, AUTOFS_DEV_IOCTL_OPENMOUNT_CMD and
+AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD the ioctlfd is validated and if it is
+not a valid descriptor or doesn't correspond to an autofs mount point
+an error of -EBADF, -ENOTTY or -EINVAL (not an autofs descriptor) is
+returned.
+
+
+The ioctls
+==========
+
+An example of an implementation which uses this interface can be seen
+in autofs version 5.0.4 and later in file lib/dev-ioctl-lib.c of the
+distribution tar available for download from kernel.org in directory
+/pub/linux/daemons/autofs/v5.
+
+The device node ioctl operations implemented by this interface are:
+
+
+AUTOFS_DEV_IOCTL_VERSION
+------------------------
+
+Get the major and minor version of the autofs4 device ioctl kernel module
+implementation. It requires an initialized struct autofs_dev_ioctl as an
+input parameter and sets the version information in the passed in structure.
+It returns 0 on success or the error -EINVAL if a version mismatch is
+detected.
+
+
+AUTOFS_DEV_IOCTL_PROTOVER_CMD and AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD
+------------------------------------------------------------------
+
+Get the major and minor version of the autofs4 protocol version understood
+by loaded module. This call requires an initialized struct autofs_dev_ioctl
+with the ioctlfd field set to a valid autofs mount point descriptor
+and sets the requested version number in structure field arg1. These
+commands return 0 on success or one of the negative error codes if
+validation fails.
+
+
+AUTOFS_DEV_IOCTL_OPENMOUNT and AUTOFS_DEV_IOCTL_CLOSEMOUNT
+----------------------------------------------------------
+
+Obtain and release a file descriptor for an autofs managed mount point
+path. The open call requires an initialized struct autofs_dev_ioctl with
+the the path field set and the size field adjusted appropriately as well
+as the arg1 field set to the device number of the autofs mount. The
+device number can be obtained from the mount options shown in
+/proc/mounts. The close call requires an initialized struct
+autofs_dev_ioct with the ioctlfd field set to the descriptor obtained
+from the open call. The release of the file descriptor can also be done
+with close(2) so any open descriptors will also be closed at process exit.
+The close call is included in the implemented operations largely for
+completeness and to provide for a consistent user space implementation.
+
+
+AUTOFS_DEV_IOCTL_READY_CMD and AUTOFS_DEV_IOCTL_FAIL_CMD
+--------------------------------------------------------
+
+Return mount and expire result status from user space to the kernel.
+Both of these calls require an initialized struct autofs_dev_ioctl
+with the ioctlfd field set to the descriptor obtained from the open
+call and the arg1 field set to the wait queue token number, received
+by user space in the foregoing mount or expire request. The arg2 field
+is set to the status to be returned. For the ready call this is always
+0 and for the fail call it is set to the errno of the operation.
+
+
+AUTOFS_DEV_IOCTL_SETPIPEFD_CMD
+------------------------------
+
+Set the pipe file descriptor used for kernel communication to the daemon.
+Normally this is set at mount time using an option but when reconnecting
+to a existing mount we need to use this to tell the autofs mount about
+the new kernel pipe descriptor. In order to protect mounts against
+incorrectly setting the pipe descriptor we also require that the autofs
+mount be catatonic (see next call).
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call and
+the arg1 field set to descriptor of the pipe. On success the call
+also sets the process group id used to identify the controlling process
+(eg. the owning automount(8) daemon) to the process group of the caller.
+
+
+AUTOFS_DEV_IOCTL_CATATONIC_CMD
+------------------------------
+
+Make the autofs mount point catatonic. The autofs mount will no longer
+issue mount requests, the kernel communication pipe descriptor is released
+and any remaining waits in the queue released.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call.
+
+
+AUTOFS_DEV_IOCTL_TIMEOUT_CMD
+----------------------------
+
+Set the expire timeout for mounts withing an autofs mount point.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call.
+
+
+AUTOFS_DEV_IOCTL_REQUESTER_CMD
+------------------------------
+
+Return the uid and gid of the last process to successfully trigger a the
+mount on the given path dentry.
+
+The call requires an initialized struct autofs_dev_ioctl with the path
+field set to the mount point in question and the size field adjusted
+appropriately as well as the arg1 field set to the device number of the
+containing autofs mount. Upon return the struct field arg1 contains the
+uid and arg2 the gid.
+
+When reconstructing an autofs mount tree with active mounts we need to
+re-connect to mounts that may have used the original process uid and
+gid (or string variations of them) for mount lookups within the map entry.
+This call provides the ability to obtain this uid and gid so they may be
+used by user space for the mount map lookups.
+
+
+AUTOFS_DEV_IOCTL_EXPIRE_CMD
+---------------------------
+
+Issue an expire request to the kernel for an autofs mount. Typically
+this ioctl is called until no further expire candidates are found.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call. In
+addition an immediate expire, independent of the mount timeout, can be
+requested by setting the arg1 field to 1. If no expire candidates can
+be found the ioctl returns -1 with errno set to EAGAIN.
+
+This call causes the kernel module to check the mount corresponding
+to the given ioctlfd for mounts that can be expired, issues an expire
+request back to the daemon and waits for completion.
+
+AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD
+------------------------------
+
+Checks if an autofs mount point is in use.
+
+The call requires an initialized struct autofs_dev_ioctl with the
+ioctlfd field set to the descriptor obtained from the open call and
+it returns the result in the arg1 field, 1 for busy and 0 otherwise.
+
+
+AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD
+---------------------------------
+
+Check if the given path is a mountpoint.
+
+The call requires an initialized struct autofs_dev_ioctl. There are two
+possible variations. Both use the path field set to the path of the mount
+point to check and the size field adjusted appropriately. One uses the
+ioctlfd field to identify a specific mount point to check while the other
+variation uses the path and optionaly arg1 set to an autofs mount type.
+The call returns 1 if this is a mount point and sets arg1 to the device
+number of the mount and field arg2 to the relevant super block magic
+number (described below) or 0 if it isn't a mountpoint. In both cases
+the the device number (as returned by new_encode_dev()) is returned
+in field arg1.
+
+If supplied with a file descriptor we're looking for a specific mount,
+not necessarily at the top of the mounted stack. In this case the path
+the descriptor corresponds to is considered a mountpoint if it is itself
+a mountpoint or contains a mount, such as a multi-mount without a root
+mount. In this case we return 1 if the descriptor corresponds to a mount
+point and and also returns the super magic of the covering mount if there
+is one or 0 if it isn't a mountpoint.
+
+If a path is supplied (and the ioctlfd field is set to -1) then the path
+is looked up and is checked to see if it is the root of a mount. If a
+type is also given we are looking for a particular autofs mount and if
+a match isn't found a fail is returned. If the the located path is the
+root of a mount 1 is returned along with the super magic of the mount
+or 0 otherwise.
+
diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index b45f3c1b8b4..295f26cd895 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -193,6 +193,5 @@ kernel source: <file:fs/ext3/>
programs: http://e2fsprogs.sourceforge.net/
http://ext2resize.sourceforge.net
-useful links: http://www.zip.com.au/~akpm/linux/ext3/ext3-usage.html
- http://www-106.ibm.com/developerworks/linux/library/l-fs7/
+useful links: http://www-106.ibm.com/developerworks/linux/library/l-fs7/
http://www-106.ibm.com/developerworks/linux/library/l-fs8/
diff --git a/Documentation/filesystems/nfsroot.txt b/Documentation/filesystems/nfsroot.txt
index 31b32917234..68baddf3c3e 100644
--- a/Documentation/filesystems/nfsroot.txt
+++ b/Documentation/filesystems/nfsroot.txt
@@ -169,7 +169,7 @@ They depend on various facilities being available:
3.1) Booting from a floppy using syslinux
When building kernels, an easy way to create a boot floppy that uses
- syslinux is to use the zdisk or bzdisk make targets which use
+ syslinux is to use the zdisk or bzdisk make targets which use zimage
and bzimage images respectively. Both targets accept the
FDARGS parameter which can be used to set the kernel command line.
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index c318a8bbb1e..4340cc82579 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -76,3 +76,9 @@ localalloc=8(*) Allows custom localalloc size in MB. If the value is too
large, the fs will silently revert it to the default.
Localalloc is not enabled for local mounts.
localflocks This disables cluster aware flock.
+inode64 Indicates that Ocfs2 is allowed to create inodes at
+ any location in the filesystem, including those which
+ will result in inode numbers occupying more than 32
+ bits of significance.
+user_xattr (*) Enables Extended User Attributes.
+nouser_xattr Disables Extended User Attributes.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index b488edad743..c032bf39e8b 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1321,6 +1321,18 @@ debugging information is displayed on console.
NMI switch that most IA32 servers have fires unknown NMI up, for example.
If a system hangs up, try pressing the NMI switch.
+panic_on_unrecovered_nmi
+------------------------
+
+The default Linux behaviour on an NMI of either memory or unknown is to continue
+operation. For many environments such as scientific computing it is preferable
+that the box is taken out and the error dealt with than an uncorrected
+parity/ECC error get propogated.
+
+A small number of systems do generate NMI's for bizarre random reasons such as
+power management so the default is off. That sysctl works like the existing
+panic controls already in that directory.
+
nmi_watchdog
------------
diff --git a/Documentation/filesystems/ramfs-rootfs-initramfs.txt b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
index 7be232b44ee..62fe9b1e089 100644
--- a/Documentation/filesystems/ramfs-rootfs-initramfs.txt
+++ b/Documentation/filesystems/ramfs-rootfs-initramfs.txt
@@ -263,7 +263,7 @@ User Mode Linux, like so:
sleep(999999999);
}
EOF
- gcc -static hello2.c -o init
+ gcc -static hello.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
diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
index 18022e249c5..b1b98870124 100644
--- a/Documentation/gpio.txt
+++ b/Documentation/gpio.txt
@@ -240,6 +240,10 @@ signal, or (b) something wrongly believes it's safe to remove drivers
needed to manage a signal that's in active use. That is, requesting a
GPIO can serve as a kind of lock.
+Some platforms may also use knowledge about what GPIOs are active for
+power management, such as by powering down unused chip sectors and, more
+easily, gating off unused clocks.
+
These two calls are optional because not not all current Linux platforms
offer such functionality in their GPIO support; a valid implementation
could return success for all gpio_request() calls. Unlike the other calls,
@@ -264,7 +268,7 @@ map between them using calls like:
/* map GPIO numbers to IRQ numbers */
int gpio_to_irq(unsigned gpio);
- /* map IRQ numbers to GPIO numbers */
+ /* map IRQ numbers to GPIO numbers (avoid using this) */
int irq_to_gpio(unsigned irq);
Those return either the corresponding number in the other namespace, or
@@ -284,7 +288,8 @@ system wakeup capabilities.
Non-error values returned from irq_to_gpio() would most commonly be used
with gpio_get_value(), for example to initialize or update driver state
-when the IRQ is edge-triggered.
+when the IRQ is edge-triggered. Note that some platforms don't support
+this reverse mapping, so you should avoid using it.
Emulating Open Drain Signals
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 1405fb69984..22efedf60c8 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -16,6 +16,9 @@ Supported adapters:
* VIA Technologies, Inc. CX700
Datasheet: available on request and under NDA from VIA
+ * VIA Technologies, Inc. VX800/VX820
+ Datasheet: available on http://linux.via.com.tw
+
Authors:
Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -49,6 +52,7 @@ Your lspci -n listing must show one of these :
device 1106:3372 (VT8237S)
device 1106:3287 (VT8251)
device 1106:8324 (CX700)
+ device 1106:8353 (VX800/VX820)
If none of these show up, you should look in the BIOS for settings like
enable ACPI / SMBus or even USB.
@@ -57,5 +61,5 @@ Except for the oldest chips (VT82C596A/B, VT82C686A and most probably
VT8231), this driver supports I2C block transactions. Such transactions
are mainly useful to read from and write to EEPROMs.
-The CX700 additionally appears to support SMBus PEC, although this driver
-doesn't implement it yet.
+The CX700/VX800/VX820 additionally appears to support SMBus PEC, although
+this driver doesn't implement it yet.
diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface
index 9dd79123ddd..3e742ba2553 100644
--- a/Documentation/i2c/dev-interface
+++ b/Documentation/i2c/dev-interface
@@ -4,6 +4,10 @@ the /dev interface. You need to load module i2c-dev for this.
Each registered i2c adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
+Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
+i2c adapters present on your system at a given time. i2cdetect is part of
+the i2c-tools package.
+
I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ...,
@@ -17,30 +21,34 @@ So let's say you want to access an i2c adapter from a C program. The
first thing to do is "#include <linux/i2c-dev.h>". Please note that
there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel
-driver code, the other one is distributed with lm_sensors and is
+driver code, the other one is distributed with i2c-tools and is
meant to be included from user-space programs. You obviously want
the second one here.
Now, you have to decide which adapter you want to access. You should
-inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
-somewhat dynamically, so you can not even assume /dev/i2c-0 is the
-first adapter.
+inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
+Adapter numbers are assigned somewhat dynamically, so you can not
+assume much about them. They can even change from one boot to the next.
Next thing, open the device file, as follows:
+
int file;
int adapter_nr = 2; /* probably dynamically determined */
char filename[20];
- sprintf(filename,"/dev/i2c-%d",adapter_nr);
- if ((file = open(filename,O_RDWR)) < 0) {
+ snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
+ file = open(filename, O_RDWR);
+ if (file < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
When you have opened the device, you must specify with what device
address you want to communicate:
+
int addr = 0x40; /* The I2C address */
- if (ioctl(file,I2C_SLAVE,addr) < 0) {
+
+ if (ioctl(file, I2C_SLAVE, addr) < 0) {
/* ERROR HANDLING; you can check errno to see what went wrong */
exit(1);
}
@@ -48,31 +56,41 @@ address you want to communicate:
Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below.
+
__u8 register = 0x10; /* Device register to access */
__s32 res;
char buf[10];
+
/* Using SMBus commands */
- res = i2c_smbus_read_word_data(file,register);
+ res = i2c_smbus_read_word_data(file, register);
if (res < 0) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* res contains the read word */
}
+
/* Using I2C Write, equivalent of
- i2c_smbus_write_word_data(file,register,0x6543) */
+ i2c_smbus_write_word_data(file, register, 0x6543) */
buf[0] = register;
buf[1] = 0x43;
buf[2] = 0x65;
- if ( write(file,buf,3) != 3) {
+ if (write(file, buf, 3) ! =3) {
/* ERROR HANDLING: i2c transaction failed */
}
+
/* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
- if (read(file,buf,1) != 1) {
+ if (read(file, buf, 1) != 1) {
/* ERROR HANDLING: i2c transaction failed */
} else {
/* buf[0] contains the read byte */
}
+Note that only a subset of the I2C and SMBus protocols can be achieved by
+the means of read() and write() calls. In particular, so-called combined
+transactions (mixing read and write messages in the same transaction)
+aren't supported. For this reason, this interface is almost never used by
+user-space programs.
+
IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!
@@ -80,31 +98,29 @@ IMPORTANT: because of the use of inline functions, you *have* to use
Full interface description
==========================
-The following IOCTLs are defined and fully supported
-(see also i2c-dev.h):
+The following IOCTLs are defined:
-ioctl(file,I2C_SLAVE,long addr)
+ioctl(file, I2C_SLAVE, long addr)
Change slave address. The address is passed in the 7 lower bits of the
argument (except for 10 bit addresses, passed in the 10 lower bits in this
case).
-ioctl(file,I2C_TENBIT,long select)
+ioctl(file, I2C_TENBIT, long select)
Selects ten bit addresses if select not equals 0, selects normal 7 bit
addresses if select equals 0. Default 0. This request is only valid
if the adapter has I2C_FUNC_10BIT_ADDR.
-ioctl(file,I2C_PEC,long select)
+ioctl(file, I2C_PEC, long select)
Selects SMBus PEC (packet error checking) generation and verification
if select not equals 0, disables if select equals 0. Default 0.
Used only for SMBus transactions. This request only has an effect if the
the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
doesn't have any effect.
-ioctl(file,I2C_FUNCS,unsigned long *funcs)
+ioctl(file, I2C_FUNCS, unsigned long *funcs)
Gets the adapter functionality and puts it in *funcs.
-ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
-
+ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
Do combined read/write transaction without stop in between.
Only valid if the adapter has I2C_FUNC_I2C. The argument is
a pointer to a
@@ -120,10 +136,9 @@ ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
The slave address and whether to use ten bit address mode has to be
set in each message, overriding the values set with the above ioctl's.
-
-Other values are NOT supported at this moment, except for I2C_SMBUS,
-which you should never directly call; instead, use the access functions
-below.
+ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
+ Not meant to be called directly; instead, use the access functions
+ below.
You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
@@ -148,7 +163,52 @@ what happened. The 'write' transactions return 0 on success; the
returns the number of values read. The block buffers need not be longer
than 32 bytes.
-The above functions are all macros, that resolve to calls to the
-i2c_smbus_access function, that on its turn calls a specific ioctl
+The above functions are all inline functions, that resolve to calls to
+the i2c_smbus_access function, that on its turn calls a specific ioctl
with the data in a specific format. Read the source code if you
want to know what happens behind the screens.
+
+
+Implementation details
+======================
+
+For the interested, here's the code flow which happens inside the kernel
+when you use the /dev interface to I2C:
+
+1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
+section "C example" above.
+
+2* These open() and ioctl() calls are handled by the i2c-dev kernel
+driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
+respectively. You can think of i2c-dev as a generic I2C chip driver
+that can be programmed from user-space.
+
+3* Some ioctl() calls are for administrative tasks and are handled by
+i2c-dev directly. Examples include I2C_SLAVE (set the address of the
+device you want to access) and I2C_PEC (enable or disable SMBus error
+checking on future transactions.)
+
+4* Other ioctl() calls are converted to in-kernel function calls by
+i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
+functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
+performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().
+
+The i2c-dev driver is responsible for checking all the parameters that
+come from user-space for validity. After this point, there is no
+difference between these calls that came from user-space through i2c-dev
+and calls that would have been performed by kernel I2C chip drivers
+directly. This means that I2C bus drivers don't need to implement
+anything special to support access from user-space.
+
+5* These i2c-core.c/i2c.h functions are wrappers to the actual
+implementation of your I2C bus driver. Each adapter must declare
+callback functions implementing these standard calls.
+i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
+while i2c-core.c:i2c_smbus_xfer() calls either
+adapter.algo->smbus_xfer() if it is implemented, or if not,
+i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
+i2c_adapter.algo->master_xfer().
+
+After your I2C bus driver has processed these requests, execution runs
+up the call chain, with almost no processing done, except by i2c-dev to
+package the returned data, if any, in suitable format for the ioctl.
diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol
index 24bfb65da17..9df47441f0e 100644
--- a/Documentation/i2c/smbus-protocol
+++ b/Documentation/i2c/smbus-protocol
@@ -109,8 +109,8 @@ specified through the Comm byte.
S Addr Wr [A] Comm [A] DataLow [A] DataHigh [A] P
-SMBus Process Call
-==================
+SMBus Process Call: i2c_smbus_process_call()
+=============================================
This command selects a device register (through the Comm byte), sends
16 bits of data to it, and reads 16 bits of data in return.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index 6b61b3a2e90..d73ee117a8c 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -606,6 +606,8 @@ SMBus communication
extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
u8 command, u16 value);
+ extern s32 i2c_smbus_process_call(struct i2c_client *client,
+ u8 command, u16 value);
extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
u8 command, u8 *values);
extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
@@ -621,8 +623,6 @@ These ones were removed from i2c-core because they had no users, but could
be added back later if needed:
extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
- extern s32 i2c_smbus_process_call(struct i2c_client * client,
- u8 command, u16 value);
extern s32 i2c_smbus_block_process_call(struct i2c_client *client,
u8 command, u8 length,
u8 *values)
diff --git a/Documentation/ia64/kvm.txt b/Documentation/ia64/kvm.txt
index 914d07f4926..84f7cb3d5be 100644
--- a/Documentation/ia64/kvm.txt
+++ b/Documentation/ia64/kvm.txt
@@ -1,7 +1,8 @@
-Currently, kvm module in EXPERIMENTAL stage on IA64. This means that
-interfaces are not stable enough to use. So, plase had better don't run
-critical applications in virtual machine. We will try our best to make it
-strong in future versions!
+Currently, kvm module is in EXPERIMENTAL stage on IA64. This means that
+interfaces are not stable enough to use. So, please don't run critical
+applications in virtual machine.
+We will try our best to improve it in future versions!
+
Guide: How to boot up guests on kvm/ia64
This guide is to describe how to enable kvm support for IA-64 systems.
diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt
index 6387d3decf8..c725d33b316 100644
--- a/Documentation/networking/cs89x0.txt
+++ b/Documentation/networking/cs89x0.txt
@@ -3,7 +3,7 @@ NOTE
----
This document was contributed by Cirrus Logic for kernel 2.2.5. This version
-has been updated for 2.3.48 by Andrew Morton <andrewm@uow.edu.au>
+has been updated for 2.3.48 by Andrew Morton.
Cirrus make a copy of this driver available at their website, as
described below. In general, you should use the driver version which
@@ -690,7 +690,7 @@ latest drivers and technical publications.
6.4 Current maintainer
In February 2000 the maintenance of this driver was assumed by Andrew
-Morton <akpm@zip.com.au>
+Morton.
6.5 Kernel module parameters
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
index 6356d3faed3..bd70976b816 100644
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -1,5 +1,5 @@
Documentation/networking/vortex.txt
-Andrew Morton <andrewm@uow.edu.au>
+Andrew Morton
30 April 2000
@@ -11,7 +11,7 @@ The driver was written by Donald Becker <becker@scyld.com>
Don is no longer the prime maintainer of this version of the driver.
Please report problems to one or more of:
- Andrew Morton <akpm@osdl.org>
+ Andrew Morton
Netdev mailing list <netdev@vger.kernel.org>
Linux kernel mailing list <linux-kernel@vger.kernel.org>
@@ -305,11 +305,6 @@ Donald's wake-on-LAN page:
ftp://ftp.3com.com/pub/nic/3c90x/3c90xx2.exe
-Driver updates and a detailed changelog for the modifications which
-were made for the 2.3/2,4 series kernel is available at
-
- http://www.zip.com.au/~akpm/linux/#3c59x-bc
-
Autonegotiation notes
---------------------
diff --git a/Documentation/power/regulator/machine.txt b/Documentation/power/regulator/machine.txt
index c9a35665cf7..ce3487d99ab 100644
--- a/Documentation/power/regulator/machine.txt
+++ b/Documentation/power/regulator/machine.txt
@@ -2,17 +2,8 @@ Regulator Machine Driver Interface
===================================
The regulator machine driver interface is intended for board/machine specific
-initialisation code to configure the regulator subsystem. Typical things that
-machine drivers would do are :-
+initialisation code to configure the regulator subsystem.
- 1. Regulator -> Device mapping.
- 2. Regulator supply configuration.
- 3. Power Domain constraint setting.
-
-
-
-1. Regulator -> device mapping
-==============================
Consider the following machine :-
Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
@@ -21,81 +12,82 @@ Consider the following machine :-
The drivers for consumers A & B must be mapped to the correct regulator in
order to control their power supply. This mapping can be achieved in machine
-initialisation code by calling :-
+initialisation code by creating a struct regulator_consumer_supply for
+each regulator.
+
+struct regulator_consumer_supply {
+ struct device *dev; /* consumer */
+ const char *supply; /* consumer supply - e.g. "vcc" */
+};
-int regulator_set_device_supply(const char *regulator, struct device *dev,
- const char *supply);
+e.g. for the machine above
-and is shown with the following code :-
+static struct regulator_consumer_supply regulator1_consumers[] = {
+{
+ .dev = &platform_consumerB_device.dev,
+ .supply = "Vcc",
+},};
-regulator_set_device_supply("Regulator-1", devB, "Vcc");
-regulator_set_device_supply("Regulator-2", devA, "Vcc");
+static struct regulator_consumer_supply regulator2_consumers[] = {
+{
+ .dev = &platform_consumerA_device.dev,
+ .supply = "Vcc",
+},};
This maps Regulator-1 to the 'Vcc' supply for Consumer B and maps Regulator-2
to the 'Vcc' supply for Consumer A.
-
-2. Regulator supply configuration.
-==================================
-Consider the following machine (again) :-
-
- Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
- |
- +-> [Consumer B @ 3.3V]
+Constraints can now be registered by defining a struct regulator_init_data
+for each regulator power domain. This structure also maps the consumers
+to their supply regulator :-
+
+static struct regulator_init_data regulator1_data = {
+ .constraints = {
+ .min_uV = 3300000,
+ .max_uV = 3300000,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(regulator1_consumers),
+ .consumer_supplies = regulator1_consumers,
+};
Regulator-1 supplies power to Regulator-2. This relationship must be registered
with the core so that Regulator-1 is also enabled when Consumer A enables it's
-supply (Regulator-2).
-
-This relationship can be register with the core via :-
-
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
-
-In this example we would use the following code :-
-
-regulator_set_supply("Regulator-2", "Regulator-1");
-
-Relationships can be queried by calling :-
-
-const char *regulator_get_supply(const char *regulator);
-
-
-3. Power Domain constraint setting.
-===================================
-Each power domain within a system has physical constraints on voltage and
-current. This must be defined in software so that the power domain is always
-operated within specifications.
-
-Consider the following machine (again) :-
-
- Regulator-1 -+-> Regulator-2 --> [Consumer A @ 1.8 - 2.0V]
- |
- +-> [Consumer B @ 3.3V]
-
-This gives us two regulators and two power domains:
-
- Domain 1: Regulator-2, Consumer B.
- Domain 2: Consumer A.
-
-Constraints can be registered by calling :-
-
-int regulator_set_platform_constraints(const char *regulator,
- struct regulation_constraints *constraints);
-
-The example is defined as follows :-
-
-struct regulation_constraints domain_1 = {
- .min_uV = 3300000,
- .max_uV = 3300000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL,
+supply (Regulator-2). The supply regulator is set by the supply_regulator_dev
+field below:-
+
+static struct regulator_init_data regulator2_data = {
+ .supply_regulator_dev = &platform_regulator1_device.dev,
+ .constraints = {
+ .min_uV = 1800000,
+ .max_uV = 2000000,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ .valid_modes_mask = REGULATOR_MODE_NORMAL,
+ },
+ .num_consumer_supplies = ARRAY_SIZE(regulator2_consumers),
+ .consumer_supplies = regulator2_consumers,
};
-struct regulation_constraints domain_2 = {
- .min_uV = 1800000,
- .max_uV = 2000000,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
- .valid_modes_mask = REGULATOR_MODE_NORMAL,
+Finally the regulator devices must be registered in the usual manner.
+
+static struct platform_device regulator_devices[] = {
+{
+ .name = "regulator",
+ .id = DCDC_1,
+ .dev = {
+ .platform_data = &regulator1_data,
+ },
+},
+{
+ .name = "regulator",
+ .id = DCDC_2,
+ .dev = {
+ .platform_data = &regulator2_data,
+ },
+},
};
+/* register regulator 1 device */
+platform_device_register(&wm8350_regulator_devices[0]);
-regulator_set_platform_constraints("Regulator-1", &domain_1);
-regulator_set_platform_constraints("Regulator-2", &domain_2);
+/* register regulator 2 device */
+platform_device_register(&wm8350_regulator_devices[1]);
diff --git a/Documentation/power/regulator/regulator.txt b/Documentation/power/regulator/regulator.txt
index a6905014359..4200accb9bb 100644
--- a/Documentation/power/regulator/regulator.txt
+++ b/Documentation/power/regulator/regulator.txt
@@ -10,11 +10,11 @@ Registration
Drivers can register a regulator by calling :-
-struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- void *reg_data);
+struct regulator_dev *regulator_register(struct device *dev,
+ struct regulator_desc *regulator_desc);
-This will register the regulators capabilities and operations the regulator
-core. The core does not touch reg_data (private to regulator driver).
+This will register the regulators capabilities and operations to the regulator
+core.
Regulators can be unregistered by calling :-
diff --git a/Documentation/power/s2ram.txt b/Documentation/power/s2ram.txt
index b05f512130e..2ebdc6091ce 100644
--- a/Documentation/power/s2ram.txt
+++ b/Documentation/power/s2ram.txt
@@ -54,3 +54,21 @@ used to run with "radeonfb" (it's an ATI Radeon mobility). It turns out
that "radeonfb" simply cannot resume that device - it tries to set the
PLL's, and it just _hangs_. Using the regular VGA console and letting X
resume it instead works fine.
+
+NOTE
+====
+pm_trace uses the system's Real Time Clock (RTC) to save the magic number.
+Reason for this is that the RTC is the only reliably available piece of
+hardware during resume operations where a value can be set that will
+survive a reboot.
+
+Consequence is that after a resume (even if it is successful) your system
+clock will have a value corresponding to the magic mumber instead of the
+correct date/time! It is therefore advisable to use a program like ntp-date
+or rdate to reset the correct date/time from an external time source when
+using this trace option.
+
+As the clock keeps ticking it is also essential that the reboot is done
+quickly after the resume failure. The trace option does not use the seconds
+or the low order bits of the minutes of the RTC, but a too long delay will
+corrupt the magic value.
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX
index 29d839ce732..e3960b8c868 100644
--- a/Documentation/powerpc/00-INDEX
+++ b/Documentation/powerpc/00-INDEX
@@ -18,10 +18,6 @@ mpc52xx.txt
- Linux 2.6.x on MPC52xx family
mpc52xx-device-tree-bindings.txt
- MPC5200 Device Tree Bindings
-ppc_htab.txt
- - info about the Linux/PPC /proc/ppc_htab entry
-smp.txt
- - use and state info about Linux/PPC on MP machines
sound.txt
- info on sound support under Linux/PPC
zImage_layout.txt
diff --git a/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt b/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt
new file mode 100644
index 00000000000..35a46536240
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/fsl/83xx-512x-pci.txt
@@ -0,0 +1,40 @@
+* Freescale 83xx and 512x PCI bridges
+
+Freescale 83xx and 512x SOCs include the same pci bridge core.
+
+83xx/512x specific notes:
+- reg: should contain two address length tuples
+ The first is for the internal pci bridge registers
+ The second is for the pci config space access registers
+
+Example (MPC8313ERDB)
+ pci0: pci@e0008500 {
+ cell-index = <1>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ /* IDSEL 0x0E -mini PCI */
+ 0x7000 0x0 0x0 0x1 &ipic 18 0x8
+ 0x7000 0x0 0x0 0x2 &ipic 18 0x8
+ 0x7000 0x0 0x0 0x3 &ipic 18 0x8
+ 0x7000 0x0 0x0 0x4 &ipic 18 0x8
+
+ /* IDSEL 0x0F - PCI slot */
+ 0x7800 0x0 0x0 0x1 &ipic 17 0x8
+ 0x7800 0x0 0x0 0x2 &ipic 18 0x8
+ 0x7800 0x0 0x0 0x3 &ipic 17 0x8
+ 0x7800 0x0 0x0 0x4 &ipic 18 0x8>;
+ interrupt-parent = <&ipic>;
+ interrupts = <66 0x8>;
+ bus-range = <0x0 0x0>;
+ ranges = <0x02000000 0x0 0x90000000 0x90000000 0x0 0x10000000
+ 0x42000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+ 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
+ clock-frequency = <66666666>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
+ compatible = "fsl,mpc8349-pci";
+ device_type = "pci";
+ };
diff --git a/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt
new file mode 100644
index 00000000000..d015dcec401
--- /dev/null
+++ b/Documentation/powerpc/dts-bindings/fsl/8xxx_gpio.txt
@@ -0,0 +1,40 @@
+GPIO controllers on MPC8xxx SoCs
+
+This is for the non-QE/CPM/GUTs GPIO controllers as found on
+8349, 8572, 8610 and compatible.
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Required properties:
+- compatible : "fsl,<CHIP>-gpio" followed by "fsl,mpc8349-gpio" for
+ 83xx, "fsl,mpc8572-gpio" for 85xx and "fsl,mpc8610-gpio" for 86xx.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+ second cell is used to specify optional parameters (currently unused).
+ - interrupts : Interrupt mapping for GPIO IRQ (currently unused).
+ - interrupt-parent : Phandle for the interrupt controller that
+ services interrupts for this device.
+- gpio-controller : Marks the port as GPIO controller.
+
+Example of gpio-controller nodes for a MPC8347 SoC:
+
+ gpio1: gpio-controller@c00 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+ reg = <0xc00 0x100>;
+ interrupts = <74 0x8>;
+ interrupt-parent = <&ipic>;
+ gpio-controller;
+ };
+
+ gpio2: gpio-controller@d00 {
+ #gpio-cells = <2>;
+ compatible = "fsl,mpc8347-gpio", "fsl,mpc8349-gpio";
+ reg = <0xd00 0x100>;
+ interrupts = <75 0x8>;
+ interrupt-parent = <&ipic>;
+ gpio-controller;
+ };
+
+See booting-without-of.txt for details of how to specify GPIO
+information for devices.
diff --git a/Documentation/powerpc/dts-bindings/fsl/dma.txt b/Documentation/powerpc/dts-bindings/fsl/dma.txt
index 86826df00e6..cc453110fc4 100644
--- a/Documentation/powerpc/dts-bindings/fsl/dma.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/dma.txt
@@ -20,7 +20,7 @@ Required properties:
- compatible : compatible list, contains 2 entries, first is
"fsl,CHIP-dma-channel", where CHIP is the processor
(mpc8349, mpc8350, etc.) and the second is
- "fsl,elo-dma-channel"
+ "fsl,elo-dma-channel". However, see note below.
- reg : <registers mapping for channel>
- cell-index : dma channel index starts at 0.
@@ -82,7 +82,7 @@ Required properties:
- compatible : compatible list, contains 2 entries, first is
"fsl,CHIP-dma-channel", where CHIP is the processor
(mpc8540, mpc8560, etc.) and the second is
- "fsl,eloplus-dma-channel"
+ "fsl,eloplus-dma-channel". However, see note below.
- cell-index : dma channel index starts at 0.
- reg : <registers mapping for channel>
- interrupts : <interrupt mapping for DMA channel IRQ>
@@ -125,3 +125,12 @@ Example:
interrupts = <17 2>;
};
};
+
+Note on DMA channel compatible properties: The compatible property must say
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel" to be used by the Elo DMA
+driver (fsldma). Any DMA channel used by fsldma cannot be used by another
+DMA driver, such as the SSI sound drivers for the MPC8610. Therefore, any DMA
+channel that should be used for another driver should not use
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel". For the SSI drivers, for
+example, the compatible property should be "fsl,ssi-dma-channel". See ssi.txt
+for more information.
diff --git a/Documentation/powerpc/dts-bindings/fsl/ssi.txt b/Documentation/powerpc/dts-bindings/fsl/ssi.txt
index d100555d488..a2d963998a6 100644
--- a/Documentation/powerpc/dts-bindings/fsl/ssi.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/ssi.txt
@@ -24,6 +24,12 @@ Required properties:
"rj-master" - r.j., SSI is clock master
"ac97-slave" - AC97 mode, SSI is clock slave
"ac97-master" - AC97 mode, SSI is clock master
+- fsl,playback-dma: phandle to a node for the DMA channel to use for
+ playback of audio. This is typically dictated by SOC
+ design. See the notes below.
+- fsl,capture-dma: phandle to a node for the DMA channel to use for
+ capture (recording) of audio. This is typically dictated
+ by SOC design. See the notes below.
Optional properties:
- codec-handle : phandle to a 'codec' node that defines an audio
@@ -36,3 +42,20 @@ Child 'codec' node required properties:
Child 'codec' node optional properties:
- clock-frequency : The frequency of the input clock, which typically
comes from an on-board dedicated oscillator.
+
+Notes on fsl,playback-dma and fsl,capture-dma:
+
+On SOCs that have an SSI, specific DMA channels are hard-wired for playback
+and capture. On the MPC8610, for example, SSI1 must use DMA channel 0 for
+playback and DMA channel 1 for capture. SSI2 must use DMA channel 2 for
+playback and DMA channel 3 for capture. The developer can choose which
+DMA controller to use, but the channels themselves are hard-wired. The
+purpose of these two properties is to represent this hardware design.
+
+The device tree nodes for the DMA channels that are referenced by
+"fsl,playback-dma" and "fsl,capture-dma" must be marked as compatible with
+"fsl,ssi-dma-channel". The SOC-specific compatible string (e.g.
+"fsl,mpc8610-dma-channel") can remain. If these nodes are left as
+"fsl,elo-dma-channel" or "fsl,eloplus-dma-channel", then the generic Elo DMA
+drivers (fsldma) will attempt to use them, and it will conflict with the
+sound drivers.
diff --git a/Documentation/powerpc/ppc_htab.txt b/Documentation/powerpc/ppc_htab.txt
deleted file mode 100644
index 8b8c7df29fa..00000000000
--- a/Documentation/powerpc/ppc_htab.txt
+++ /dev/null
@@ -1,118 +0,0 @@
- Information about /proc/ppc_htab
-=====================================================================
-
-This document and the related code was written by me (Cort Dougan), please
-email me (cort@fsmlabs.com) if you have questions, comments or corrections.
-
-Last Change: 2.16.98
-
-This entry in the proc directory is readable by all users but only
-writable by root.
-
-The ppc_htab interface is a user level way of accessing the
-performance monitoring registers as well as providing information
-about the PTE hash table.
-
-1. Reading
-
- Reading this file will give you information about the memory management
- hash table that serves as an extended tlb for page translation on the
- powerpc. It will also give you information about performance measurement
- specific to the cpu that you are using.
-
- Explanation of the 604 Performance Monitoring Fields:
- MMCR0 - the current value of the MMCR0 register
- PMC1
- PMC2 - the value of the performance counters and a
- description of what events they are counting
- which are based on MMCR0 bit settings.
- Explanation of the PTE Hash Table fields:
-
- Size - hash table size in Kb.
- Buckets - number of buckets in the table.
- Address - the virtual kernel address of the hash table base.
- Entries - the number of ptes that can be stored in the hash table.
- User/Kernel - how many pte's are in use by the kernel or user at that time.
- Overflows - How many of the entries are in their secondary hash location.
- Percent full - ratio of free pte entries to in use entries.
- Reloads - Count of how many hash table misses have occurred
- that were fixed with a reload from the linux tables.
- Should always be 0 on 603 based machines.
- Non-error Misses - Count of how many hash table misses have occurred
- that were completed with the creation of a pte in the linux
- tables with a call to do_page_fault().
- Error Misses - Number of misses due to errors such as bad address
- and permission violations. This includes kernel access of
- bad user addresses that are fixed up by the trap handler.
-
- Note that calculation of the data displayed from /proc/ppc_htab takes
- a long time and spends a great deal of time in the kernel. It would
- be quite hard on performance to read this file constantly. In time
- there may be a counter in the kernel that allows successive reads from
- this file only after a given amount of time has passed to reduce the
- possibility of a user slowing the system by reading this file.
-
-2. Writing
-
- Writing to the ppc_htab allows you to change the characteristics of
- the powerpc PTE hash table and setup performance monitoring.
-
- Resizing the PTE hash table is not enabled right now due to many
- complications with moving the hash table, rehashing the entries
- and many many SMP issues that would have to be dealt with.
-
- Write options to ppc_htab:
-
- - To set the size of the hash table to 64Kb:
-
- echo 'size 64' > /proc/ppc_htab
-
- The size must be a multiple of 64 and must be greater than or equal to
- 64.
-
- - To turn off performance monitoring:
-
- echo 'off' > /proc/ppc_htab
-
- - To reset the counters without changing what they're counting:
-
- echo 'reset' > /proc/ppc_htab
-
- Note that counting will continue after the reset if it is enabled.
-
- - To count only events in user mode or only in kernel mode:
-
- echo 'user' > /proc/ppc_htab
- ...or...
- echo 'kernel' > /proc/ppc_htab
-
- Note that these two options are exclusive of one another and the
- lack of either of these options counts user and kernel.
- Using 'reset' and 'off' reset these flags.
-
- - The 604 has 2 performance counters which can each count events from
- a specific set of events. These sets are disjoint so it is not
- possible to count _any_ combination of 2 events. One event can
- be counted by PMC1 and one by PMC2.
-
- To start counting a particular event use:
-
- echo 'event' > /proc/ppc_htab
-
- and choose from these events:
-
- PMC1
- ----
- 'ic miss' - instruction cache misses
- 'dtlb' - data tlb misses (not hash table misses)
-
- PMC2
- ----
- 'dc miss' - data cache misses
- 'itlb' - instruction tlb misses (not hash table misses)
- 'load miss time' - cycles to complete a load miss
-
-3. Bugs
-
- The PMC1 and PMC2 counters can overflow and give no indication of that
- in /proc/ppc_htab.
diff --git a/Documentation/powerpc/smp.txt b/Documentation/powerpc/smp.txt
deleted file mode 100644
index 5b581b849ff..00000000000
--- a/Documentation/powerpc/smp.txt
+++ /dev/null
@@ -1,34 +0,0 @@
- Information about Linux/PPC SMP mode
-=====================================================================
-
-This document and the related code was written by me
-(Cort Dougan, cort@fsmlabs.com) please email me if you have questions,
-comments or corrections.
-
-Last Change: 3.31.99
-
-If you want to help by writing code or testing different hardware please
-email me!
-
-1. State of Supported Hardware
-
- PowerSurge Architecture - tested on UMAX s900, Apple 9600
- The second processor on this machine boots up just fine and
- enters its idle loop. Hopefully a completely working SMP kernel
- on this machine will be done shortly.
-
- The code makes the assumption of only two processors. The changes
- necessary to work with any number would not be overly difficult but
- I don't have any machines with >2 processors so it's not high on my
- list of priorities. If anyone else would like do to the work email
- me and I can point out the places that need changed. If you have >2
- processors and don't want to add support yourself let me know and I
- can take a look into it.
-
- BeBox
- BeBox support hasn't been added to the 2.1.X kernels from 2.0.X
- but work is being done and SMP support for BeBox is in the works.
-
- CHRP
- CHRP SMP works and is fairly solid. It's been tested on the IBM F50
- with 4 processors for quite some time now.
diff --git a/Documentation/scsi/ChangeLog.megaraid b/Documentation/scsi/ChangeLog.megaraid
index 37796fe45bd..eaa4801f2ce 100644
--- a/Documentation/scsi/ChangeLog.megaraid
+++ b/Documentation/scsi/ChangeLog.megaraid
@@ -409,7 +409,7 @@ i. Function reordering so that inline functions are defined before they
megaraid_mbox_prepare_pthru, megaraid_mbox_prepare_epthru,
megaraid_busywait_mbox
- - Andrew Morton <akpm@osdl.org>, 08.19.2004
+ - Andrew Morton, 08.19.2004
linux-scsi mailing list
"Something else to clean up after inclusion: every instance of an
@@ -471,13 +471,13 @@ vi. Add support for 64-bit applications. Current drivers assume only
vii. Move the function declarations for the management module from
megaraid_mm.h to megaraid_mm.c
- - Andrew Morton <akpm@osdl.org>, 08.19.2004
+ - Andrew Morton, 08.19.2004
linux-scsi mailing list
viii. Change default values for MEGARAID_NEWGEN, MEGARAID_MM, and
MEGARAID_MAILBOX to 'n' in Kconfig.megaraid
- - Andrew Morton <akpm@osdl.org>, 08.19.2004
+ - Andrew Morton, 08.19.2004
linux-scsi mailing list
ix. replace udelay with msleep
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index bbe8dee681a..6bb916d57c9 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -96,7 +96,7 @@ Each slave device attached to the PXA must provide slave specific configuration
information via the structure "pxa2xx_spi_chip" found in
"arch/arm/mach-pxa/include/mach/pxa2xx_spi.h". The pxa2xx_spi master controller driver
will uses the configuration whenever the driver communicates with the slave
-device.
+device. All fields are optional.
struct pxa2xx_spi_chip {
u8 tx_threshold;
@@ -112,14 +112,17 @@ used to configure the SSP hardware fifo. These fields are critical to the
performance of pxa2xx_spi driver and misconfiguration will result in rx
fifo overruns (especially in PIO mode transfers). Good default values are
- .tx_threshold = 12,
- .rx_threshold = 4,
+ .tx_threshold = 8,
+ .rx_threshold = 8,
+
+The range is 1 to 16 where zero indicates "use default".
The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA
engine and is related the "spi_device.bits_per_word" field. Read and understand
the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
to determine the correct value. An SSP configured for byte-wide transfers would
-use a value of 8.
+use a value of 8. The driver will determine a reasonable default if
+dma_burst_size == 0.
The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
trailing bytes in the SSP receiver fifo. The correct value for this field is
@@ -137,7 +140,13 @@ function for asserting/deasserting a slave device chip select. If the field is
NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
configured to use SSPFRM instead.
-NSSP SALVE SAMPLE
+NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
+chipselect is dropped after each spi_transfer. Most devices need chip select
+asserted around the complete message. Use SSPFRM as a GPIO (through cs_control)
+to accomodate these chips.
+
+
+NSSP SLAVE SAMPLE
-----------------
The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
"spi_board_info.controller_data" field. Below is a sample configuration using
@@ -206,18 +215,21 @@ static void __init streetracer_init(void)
DMA and PIO I/O Support
-----------------------
-The pxa2xx_spi driver support both DMA and interrupt driven PIO message
-transfers. The driver defaults to PIO mode and DMA transfers must enabled by
-setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and
-ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero. The DMA
-mode support both coherent and stream based DMA mappings.
+The pxa2xx_spi driver supports both DMA and interrupt driven PIO message
+transfers. The driver defaults to PIO mode and DMA transfers must be enabled
+by setting the "enable_dma" flag in the "pxa2xx_spi_master" structure. The DMA
+mode supports both coherent and stream based DMA mappings.
The following logic is used to determine the type of I/O to be used on
a per "spi_transfer" basis:
-if !enable_dma or dma_burst_size == 0 then
+if !enable_dma then
always use PIO transfers
+if spi_message.len > 8191 then
+ print "rate limited" warning
+ use PIO transfers
+
if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
use coherent DMA mode
diff --git a/Documentation/w1/00-INDEX b/Documentation/w1/00-INDEX
index 5270cf4cb10..cb49802745d 100644
--- a/Documentation/w1/00-INDEX
+++ b/Documentation/w1/00-INDEX
@@ -1,5 +1,7 @@
00-INDEX
- This file
+slaves/
+ - Drivers that provide support for specific family codes.
masters/
- Individual chips providing 1-wire busses.
w1.generic
diff --git a/Documentation/w1/masters/ds2490 b/Documentation/w1/masters/ds2490
index 239f9ae0184..28176def3d6 100644
--- a/Documentation/w1/masters/ds2490
+++ b/Documentation/w1/masters/ds2490
@@ -16,3 +16,55 @@ 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.
+
+Notes and limitations.
+- The weak pullup current is a minimum of 0.9mA and maximum of 6.0mA.
+- The 5V strong pullup is supported with a minimum of 5.9mA and a
+ maximum of 30.4 mA. (From DS2490.pdf)
+- While the ds2490 supports a hardware search the code doesn't take
+ advantage of it (in tested case it only returned first device).
+- The hardware will detect when devices are attached to the bus on the
+ next bus (reset?) operation, however only a message is printed as
+ the core w1 code doesn't make use of the information. Connecting
+ one device tends to give multiple new device notifications.
+- The number of USB bus transactions could be reduced if w1_reset_send
+ was added to the API. The name is just a suggestion. It would take
+ a write buffer and a read buffer (along with sizes) as arguments.
+ The ds2490 block I/O command supports reset, write buffer, read
+ buffer, and strong pullup all in one command, instead of the current
+ 1 reset bus, 2 write the match rom command and slave rom id, 3 block
+ write and read data. The write buffer needs to have the match rom
+ command and slave rom id prepended to the front of the requested
+ write buffer, both of which are known to the driver.
+- The hardware supports normal, flexible, and overdrive bus
+ communication speeds, but only the normal is supported.
+- The registered w1_bus_master functions don't define error
+ conditions. If a bus search is in progress and the ds2490 is
+ removed it can produce a good amount of error output before the bus
+ search finishes.
+- The hardware supports detecting some error conditions, such as
+ short, alarming presence on reset, and no presence on reset, but the
+ driver doesn't query those values.
+- The ds2490 specification doesn't cover short bulk in reads in
+ detail, but my observation is if fewer bytes are requested than are
+ available, the bulk read will return an error and the hardware will
+ clear the entire bulk in buffer. It would be possible to read the
+ maximum buffer size to not run into this error condition, only extra
+ bytes in the buffer is a logic error in the driver. The code should
+ should match reads and writes as well as data sizes. Reads and
+ writes are serialized and the status verifies that the chip is idle
+ (and data is available) before the read is executed, so it should
+ not happen.
+- Running x86_64 2.6.24 UHCI under qemu 0.9.0 under x86_64 2.6.22-rc6
+ with a OHCI controller, ds2490 running in the guest would operate
+ normally the first time the module was loaded after qemu attached
+ the ds2490 hardware, but if the module was unloaded, then reloaded
+ most of the time one of the bulk out or in, and usually the bulk in
+ would fail. qemu sets a 50ms timeout and the bulk in would timeout
+ even when the status shows data available. A bulk out write would
+ show a successful completion, but the ds2490 status register would
+ show 0 bytes written. Detaching qemu from the ds2490 hardware and
+ reattaching would clear the problem. usbmon output in the guest and
+ host did not explain the problem. My guess is a bug in either qemu
+ or the host OS and more likely the host OS.
+-- 03-06-2008 David Fries <David@Fries.net>
diff --git a/Documentation/w1/slaves/00-INDEX b/Documentation/w1/slaves/00-INDEX
new file mode 100644
index 00000000000..f8101d6b07b
--- /dev/null
+++ b/Documentation/w1/slaves/00-INDEX
@@ -0,0 +1,4 @@
+00-INDEX
+ - This file
+w1_therm
+ - The Maxim/Dallas Semiconductor ds18*20 temperature sensor.
diff --git a/Documentation/w1/slaves/w1_therm b/Documentation/w1/slaves/w1_therm
new file mode 100644
index 00000000000..0403aaaba87
--- /dev/null
+++ b/Documentation/w1/slaves/w1_therm
@@ -0,0 +1,41 @@
+Kernel driver w1_therm
+====================
+
+Supported chips:
+ * Maxim ds18*20 based temperature sensors.
+
+Author: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
+
+
+Description
+-----------
+
+w1_therm provides basic temperature conversion for ds18*20 devices.
+supported family codes:
+W1_THERM_DS18S20 0x10
+W1_THERM_DS1822 0x22
+W1_THERM_DS18B20 0x28
+
+Support is provided through the sysfs w1_slave file. Each open and
+read sequence will initiate a temperature conversion then provide two
+lines of ASCII output. The first line contains the nine hex bytes
+read along with a calculated crc value and YES or NO if it matched.
+If the crc matched the returned values are retained. The second line
+displays the retained values along with a temperature in millidegrees
+Centigrade after t=.
+
+Parasite powered devices are limited to one slave performing a
+temperature conversion at a time. If none of the devices are parasite
+powered it would be possible to convert all the devices at the same
+time and then go back to read individual sensors. That isn't
+currently supported. The driver also doesn't support reduced
+precision (which would also reduce the conversion time).
+
+The module parameter strong_pullup can be set to 0 to disable the
+strong pullup or 1 to enable. If enabled the 5V strong pullup will be
+enabled when the conversion is taking place provided the master driver
+must support the strong pullup (or it falls back to a pullup
+resistor). The DS18b20 temperature sensor specification lists a
+maximum current draw of 1.5mA and that a 5k pullup resistor is not
+sufficient. The strong pullup is designed to provide the additional
+current required.
diff --git a/Documentation/w1/w1.generic b/Documentation/w1/w1.generic
index 4c6509dd478..e3333eec432 100644
--- a/Documentation/w1/w1.generic
+++ b/Documentation/w1/w1.generic
@@ -79,10 +79,13 @@ w1 master sysfs interface
<xx-xxxxxxxxxxxxx> - a directory for a found device. The format is family-serial
bus - (standard) symlink to the w1 bus
driver - (standard) symlink to the w1 driver
+w1_master_add - Manually register a slave device
w1_master_attempts - the number of times a search was attempted
w1_master_max_slave_count
- the maximum slaves that may be attached to a master
w1_master_name - the name of the device (w1_bus_masterX)
+w1_master_pullup - 5V strong pullup 0 enabled, 1 disabled
+w1_master_remove - Manually remove a slave device
w1_master_search - the number of searches left to do, -1=continual (default)
w1_master_slave_count
- the number of slaves found
@@ -90,7 +93,13 @@ w1_master_slaves - the names of the slaves, one per line
w1_master_timeout - the delay in seconds between searches
If you have a w1 bus that never changes (you don't add or remove devices),
-you can set w1_master_search to a positive value to disable searches.
+you can set the module parameter search_count to a small positive number
+for an initially small number of bus searches. Alternatively it could be
+set to zero, then manually add the slave device serial numbers by
+w1_master_add device file. The w1_master_add and w1_master_remove files
+generally only make sense when searching is disabled, as a search will
+redetect manually removed devices that are present and timeout manually
+added devices that aren't on the bus.
w1 slave sysfs interface
diff --git a/MAINTAINERS b/MAINTAINERS
index 988b0a85289..df20e29c793 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1629,6 +1629,11 @@ P: Christopher Hoover
M: ch@murgatroid.com, ch@hpl.hp.com
S: Maintained
+EPSON S1D13XXX FRAMEBUFFER DRIVER
+P: Kristoffer Ericson
+M: kristoffer.ericson@gmail.com
+S: Maintained
+
ETHEREXPRESS-16 NETWORK DRIVER
P: Philip Blundell
M: philb@gnu.org
@@ -4089,7 +4094,7 @@ W: http://tpmdd.sourceforge.net
P: Marcel Selhorst
M: tpm@selhorst.net
W: http://www.prosec.rub.de/tpm/
-L: tpmdd-devel@lists.sourceforge.net
+L: tpmdd-devel@lists.sourceforge.net (moderated for non-subscribers)
S: Maintained
TRIVIAL PATCHES
@@ -4480,6 +4485,13 @@ W: http://kernel.org/~kzak/util-linux-ng/
T: git://git.kernel.org/pub/scm/utils/util-linux-ng/util-linux-ng.git
S: Maintained
+UVESAFB DRIVER
+P: Michal Januszewski
+M: spock@gentoo.org
+L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+W: http://dev.gentoo.org/~spock/projects/uvesafb/
+S: Maintained
+
VFAT/FAT/MSDOS FILESYSTEM
P: OGAWA Hirofumi
M: hirofumi@mail.parknet.co.jp
@@ -4497,6 +4509,14 @@ M: khali@linux-fr.org
L: i2c@lm-sensors.org
S: Maintained
+VIA UNICHROME(PRO)/CHROME9 FRAMEBUFFER DRIVER
+P: Joseph Chan
+M: JosephChan@via.com.tw
+P: Scott Fang
+M: ScottFang@viatech.com.cn
+L: linux-fbdev-devel@lists.sourceforge.net (moderated for non-subscribers)
+S: Maintained
+
VIA VELOCITY NETWORK DRIVER
P: Francois Romieu
M: romieu@fr.zoreil.com
@@ -4520,10 +4540,11 @@ S: Maintained
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
P: Liam Girdwood
-M: lg@opensource.wolfsonmicro.com
+M: lrg@slimlogic.co.uk
P: Mark Brown
M: broonie@opensource.wolfsonmicro.com
W: http://opensource.wolfsonmicro.com/node/15
+W: http://www.slimlogic.co.uk/?page_id=5
T: git kernel.org/pub/scm/linux/kernel/git/lrg/voltage-2.6.git
S: Supported
diff --git a/arch/Kconfig b/arch/Kconfig
index 0267babe5eb..e6ab550bceb 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -28,7 +28,7 @@ config OPROFILE_IBS
If unsure, say N.
config HAVE_OPROFILE
- def_bool n
+ bool
config KPROBES
bool "Kprobes"
@@ -42,7 +42,7 @@ config KPROBES
If in doubt, say "N".
config HAVE_EFFICIENT_UNALIGNED_ACCESS
- def_bool n
+ bool
help
Some architectures are unable to perform unaligned accesses
without the use of get_unaligned/put_unaligned. Others are
@@ -65,13 +65,13 @@ config KRETPROBES
depends on KPROBES && HAVE_KRETPROBES
config HAVE_IOREMAP_PROT
- def_bool n
+ bool
config HAVE_KPROBES
- def_bool n
+ bool
config HAVE_KRETPROBES
- def_bool n
+ bool
#
# An arch should select this if it provides all these things:
@@ -89,16 +89,16 @@ config HAVE_KRETPROBES
# signal delivery calls tracehook_signal_handler()
#
config HAVE_ARCH_TRACEHOOK
- def_bool n
+ bool
config HAVE_DMA_ATTRS
- def_bool n
+ bool
config USE_GENERIC_SMP_HELPERS
- def_bool n
+ bool
config HAVE_CLK
- def_bool n
+ bool
help
The <linux/clk.h> calls support software clock gating and
thus are a key power management tool on many systems.
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index ee35226c44e..a0f642b6a4b 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -222,8 +222,7 @@ config ALPHA_MIATA
bool "Miata"
help
The Digital PersonalWorkStation (PWS 433a, 433au, 500a, 500au, 600a,
- or 600au). There is an Installation HOWTO for this hardware at
- <http://eijk.homelinux.org/~stefan/miata.html>.
+ or 600au).
config ALPHA_MIKASA
bool "Mikasa"
diff --git a/arch/alpha/include/asm/a.out.h b/arch/alpha/include/asm/a.out.h
index 02ce8473870..acdc681231c 100644
--- a/arch/alpha/include/asm/a.out.h
+++ b/arch/alpha/include/asm/a.out.h
@@ -95,7 +95,7 @@ struct exec
Worse, we have to notice the start address before swapping to use
/sbin/loader, which of course is _not_ a TASO application. */
#define SET_AOUT_PERSONALITY(BFPM, EX) \
- set_personality (((BFPM->sh_bang || EX.ah.entry < 0x100000000L \
+ set_personality (((BFPM->taso || EX.ah.entry < 0x100000000L \
? ADDR_LIMIT_32BIT : 0) | PER_OSF4))
#endif /* __KERNEL__ */
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index 2179c602032..b9094da05d7 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -41,13 +41,6 @@ mk_iommu_pte(unsigned long paddr)
return (paddr >> (PAGE_SHIFT-1)) | 1;
}
-static inline long
-calc_npages(long bytes)
-{
- return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
-}
-
-
/* Return the minimum of MAX or the first power of two larger
than main memory. */
@@ -287,7 +280,7 @@ pci_map_single_1(struct pci_dev *pdev, void *cpu_addr, size_t size,
if (!arena || arena->dma_base + arena->size - 1 > max_dma)
arena = hose->sg_isa;
- npages = calc_npages((paddr & ~PAGE_MASK) + size);
+ npages = iommu_num_pages(paddr, size, PAGE_SIZE);
/* Force allocation to 64KB boundary for ISA bridges. */
if (pdev && pdev == isa_bridge)
@@ -387,7 +380,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
BUG();
}
- npages = calc_npages((dma_addr & ~PAGE_MASK) + size);
+ npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
spin_lock_irqsave(&arena->lock, flags);
@@ -580,7 +573,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
contiguous. */
paddr &= ~PAGE_MASK;
- npages = calc_npages(paddr + size);
+ npages = iommu_num_pages(paddr, size, PAGE_SIZE);
dma_ofs = iommu_arena_alloc(dev, arena, npages, 0);
if (dma_ofs < 0) {
/* If we attempted a direct map above but failed, die. */
@@ -616,7 +609,7 @@ sg_fill(struct device *dev, struct scatterlist *leader, struct scatterlist *end,
sg++;
}
- npages = calc_npages((paddr & ~PAGE_MASK) + size);
+ npages = iommu_num_pages(paddr, size, PAGE_SIZE);
paddr &= PAGE_MASK;
for (i = 0; i < npages; ++i, paddr += PAGE_SIZE)
@@ -775,7 +768,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
DBGA(" (%ld) sg [%lx,%lx]\n",
sg - end + nents, addr, size);
- npages = calc_npages((addr & ~PAGE_MASK) + size);
+ npages = iommu_num_pages(addr, size, PAGE_SIZE);
ofs = (addr - arena->dma_base) >> PAGE_SHIFT;
iommu_arena_free(arena, ofs, npages);
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 06b6fdab639..e657c45d91d 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -27,6 +27,7 @@
#include <linux/cache.h>
#include <linux/profile.h>
#include <linux/bitops.h>
+#include <linux/cpu.h>
#include <asm/hwrpb.h>
#include <asm/ptrace.h>
diff --git a/arch/arm/mach-integrator/cpu.c b/arch/arm/mach-integrator/cpu.c
index e4f72d202cc..44d4c2e8207 100644
--- a/arch/arm/mach-integrator/cpu.c
+++ b/arch/arm/mach-integrator/cpu.c
@@ -184,7 +184,6 @@ static int integrator_cpufreq_init(struct cpufreq_policy *policy)
{
/* set default policy and cpuinfo */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.max_freq = 160000;
policy->cpuinfo.min_freq = 12000;
policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 2ced6d9984d..adfcd7b5139 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -476,6 +476,10 @@ static struct i2c_board_info __initdata h3_i2c_board_info[] = {
I2C_BOARD_INFO("tps65013", 0x48),
/* .irq = OMAP_GPIO_IRQ(??), */
},
+ {
+ I2C_BOARD_INFO("isp1301_omap", 0x2d),
+ .irq = OMAP_GPIO_IRQ(14),
+ },
};
static struct omap_gpio_switch h3_gpio_switches[] __initdata = {
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index d4e3b6fc470..2fef2c84508 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -18,6 +18,7 @@
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
+#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/err.h>
#include <linux/clk.h>
@@ -391,6 +392,13 @@ static struct omap_board_config_kernel h4_config[] = {
{ OMAP_TAG_LCD, &h4_lcd_config },
};
+static struct i2c_board_info __initdata h4_i2c_board_info[] = {
+ {
+ I2C_BOARD_INFO("isp1301_omap", 0x2d),
+ .irq = OMAP_GPIO_IRQ(125),
+ },
+};
+
static void __init omap_h4_init(void)
{
/*
@@ -411,6 +419,9 @@ static void __init omap_h4_init(void)
}
#endif
+ i2c_register_board_info(1, h4_i2c_board_info,
+ ARRAY_SIZE(h4_i2c_board_info));
+
platform_add_devices(h4_devices, ARRAY_SIZE(h4_devices));
omap_board_config = h4_config;
omap_board_config_size = ARRAY_SIZE(h4_config);
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
index d82528e74bd..1f272ea83f3 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
@@ -335,9 +335,6 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy)
pxa27x_guess_max_freq();
/* set default policy and cpuinfo */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
- if (cpu_is_pxa25x())
- policy->policy = CPUFREQ_POLICY_PERFORMANCE;
policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
policy->cur = get_clk_frequency_khz(0); /* current freq */
policy->min = policy->max = policy->cur;
diff --git a/arch/arm/mach-pxa/cpufreq-pxa3xx.c b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
index 1ea0c9c0ada..968c8309ec3 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa3xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa3xx.c
@@ -210,7 +210,6 @@ static __init int pxa3xx_cpufreq_init(struct cpufreq_policy *policy)
int ret = -EINVAL;
/* set default policy and cpuinfo */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 104000;
policy->cpuinfo.max_freq = (cpu_is_pxa320()) ? 806000 : 624000;
policy->cpuinfo.transition_latency = 1000; /* FIXME: 1 ms, assumed */
diff --git a/arch/arm/mach-s3c2410/include/mach/spi.h b/arch/arm/mach-s3c2410/include/mach/spi.h
index 921b13b4f0a..46d46f5b99f 100644
--- a/arch/arm/mach-s3c2410/include/mach/spi.h
+++ b/arch/arm/mach-s3c2410/include/mach/spi.h
@@ -18,6 +18,7 @@ struct s3c2410_spi_info {
unsigned int num_cs; /* total chipselects */
int bus_num; /* bus number to use. */
+ void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);
void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);
};
diff --git a/arch/arm/mach-sa1100/cpu-sa1100.c b/arch/arm/mach-sa1100/cpu-sa1100.c
index f7fa03478ef..244d5956312 100644
--- a/arch/arm/mach-sa1100/cpu-sa1100.c
+++ b/arch/arm/mach-sa1100/cpu-sa1100.c
@@ -224,7 +224,6 @@ static int __init sa1100_cpu_init(struct cpufreq_policy *policy)
if (policy->cpu != 0)
return -EINVAL;
policy->cur = policy->min = policy->max = sa11x0_getspeed(0);
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.min_freq = 59000;
policy->cpuinfo.max_freq = 287000;
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/arch/avr32/mach-at32ap/cpufreq.c b/arch/avr32/mach-at32ap/cpufreq.c
index 5dd8d25428b..d84efe4984a 100644
--- a/arch/avr32/mach-at32ap/cpufreq.c
+++ b/arch/avr32/mach-at32ap/cpufreq.c
@@ -87,7 +87,6 @@ static int __init at32_cpufreq_driver_init(struct cpufreq_policy *policy)
policy->cur = at32_get_speed(0);
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
printk("cpufreq: AT32AP CPU frequency driver\n");
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
index 75cdad291e8..c22c47b6012 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -158,8 +158,6 @@ static int __init __bfin_cpu_init(struct cpufreq_policy *policy)
dpm_state_table[index].tscale);
}
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
-
policy->cpuinfo.transition_latency = (bfin_read_PLL_LOCKCNT() / (sclk / 1000000)) * 1000;
/*Now ,only support one cpu */
policy->cur = cclk;
diff --git a/arch/cris/arch-v32/mach-a3/cpufreq.c b/arch/cris/arch-v32/mach-a3/cpufreq.c
index 8e5a3cab8ad..ee391ecb5bc 100644
--- a/arch/cris/arch-v32/mach-a3/cpufreq.c
+++ b/arch/cris/arch-v32/mach-a3/cpufreq.c
@@ -85,7 +85,6 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
int result;
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = cris_freq_get_cpu_frequency(0);
diff --git a/arch/cris/arch-v32/mach-fs/cpufreq.c b/arch/cris/arch-v32/mach-fs/cpufreq.c
index d57631c0d8d..58bd71e5bda 100644
--- a/arch/cris/arch-v32/mach-fs/cpufreq.c
+++ b/arch/cris/arch-v32/mach-fs/cpufreq.c
@@ -81,7 +81,6 @@ static int cris_freq_cpu_init(struct cpufreq_policy *policy)
int result;
/* cpuinfo and default policy values */
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 1000000; /* 1ms */
policy->cur = cris_freq_get_cpu_frequency(0);
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index d1113c5031f..be722fc1acf 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -211,7 +211,7 @@ 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 __user *name, int nlen,
+static int cmode_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -314,7 +314,7 @@ 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 __user *name, int nlen,
+static int p0_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -358,7 +358,7 @@ 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 __user *name, int nlen,
+static int cm_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 107cb5bb9f3..c7966746fbf 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -62,6 +62,10 @@ config GENERIC_TIME
bool
default y
+config GENERIC_BUG
+ bool
+ depends on BUG
+
config TIME_LOW_RES
bool
default y
diff --git a/arch/h8300/Kconfig.cpu b/arch/h8300/Kconfig.cpu
index 582797db960..b65dcfe51d9 100644
--- a/arch/h8300/Kconfig.cpu
+++ b/arch/h8300/Kconfig.cpu
@@ -1,5 +1,7 @@
menu "Processor type and features"
+source "kernel/time/Kconfig"
+
choice
prompt "H8/300 platform"
default H8300H_GENERIC
@@ -11,6 +13,7 @@ config H8300H_GENERIC
config H8300H_AKI3068NET
bool "AE-3068/69"
+ select CONFIG_H83068
help
AKI-H8/3068F / AKI-H8/3069F Flashmicom LAN Board Support
More Information. (Japanese Only)
@@ -21,6 +24,7 @@ config H8300H_AKI3068NET
config H8300H_H8MAX
bool "H8MAX"
+ select CONFIG_H83068
help
H8MAX Evaluation Board Support
More Information. (Japanese Only)
@@ -28,6 +32,7 @@ config H8300H_H8MAX
config H8300H_SIM
bool "H8/300H Simulator"
+ select CONFIG_H83007
help
GDB Simulator Support
More Information.
@@ -40,6 +45,7 @@ config H8S_GENERIC
config H8S_EDOSK2674
bool "EDOSK-2674"
+ select CONFIG_H8S2768
help
Renesas EDOSK-2674 Evaluation Board Support
More Information.
@@ -55,44 +61,37 @@ config H8S_SIM
endchoice
-if (H8300H_GENERIC || H8S_GENERIC)
-menu "Detail Selection"
-if (H8300H_GENERIC)
choice
prompt "CPU Selection"
config H83002
bool "H8/3001,3002,3003"
+ select CPU_H8300H
config H83007
bool "H8/3006,3007"
+ select CPU_H8300H
config H83048
bool "H8/3044,3045,3046,3047,3048,3052"
+ select CPU_H8300H
config H83068
bool "H8/3065,3066,3067,3068,3069"
-endchoice
-endif
-
-if (H8S_GENERIC)
-choice
- prompt "CPU Selection"
+ select CPU_H8300H
config H8S2678
bool "H8S/2670,2673,2674R,2675,2676"
+ select CPU_H8S
+
endchoice
-endif
config CPU_CLOCK
int "CPU Clock Frequency (/1KHz)"
default "20000"
help
CPU Clock Frequency divide to 1000
-endmenu
-endif
-if (H8300H_GENERIC || H8S_GENERIC || H8300H_SIM || H8S_SIM || H8S_EDOSK2674)
choice
prompt "Kernel executes from"
---help---
@@ -107,75 +106,61 @@ config ROMKERNEL
bool "ROM"
help
The kernel will be resident in FLASH/ROM when running.
-
endchoice
-endif
-if (H8300H_AKI3068NET)
-config H83068
- bool
- default y
-config CPU_CLOCK
- int
- default "20000"
-
-config RAMKERNEL
+config CPU_H8300H
bool
+ depends on (H83002 || H83007 || H83048 || H83068)
default y
-endif
-if (H8300H_H8MAX)
-config H83068
+config CPU_H8S
bool
+ depends on H8S2678
default y
-config CPU_CLOCK
- int
- default 25000
+choice
+ prompt "Timer"
+config H8300_TIMER8
+ bool "8bit timer (2ch cascade)"
+ depends on (H83007 || H83068 || H8S2678)
-config RAMKERNEL
- bool
- default y
-endif
+config H8300_TIMER16
+ bool "16bit timer"
+ depends on (H83007 || H83068)
-if (H8300H_SIM)
-config H83007
- bool
- default y
+config H8300_ITU
+ bool "ITU"
+ depends on (H83002 || H83048)
-config CPU_CLOCK
- int
- default "16000"
-endif
+config H8300_TPU
+ bool "TPU"
+ depends on H8S2678
+endchoice
-if (H8S_EDOSK2674)
-config H8S2678
- bool
- default y
-config CPU_CLOCK
- int
- default 33000
+if H8300_TIMER8
+choice
+ prompt "Timer Channel"
+config H8300_TIMER8_CH0
+ bool "Channel 0"
+config H8300_TIMER8_CH2
+ bool "Channel 2"
+ depends on CPU_H8300H
+endchoice
endif
-if (H8S_SIM)
-config H8S2678
- bool
- default y
-config CPU_CLOCK
- int
- default 33000
-endif
+config H8300_TIMER16_CH
+ int "16bit timer channel (0 - 2)"
+ depends on H8300_TIMER16
+ range 0 2
-config CPU_H8300H
- bool
- depends on (H83002 || H83007 || H83048 || H83068)
- default y
+config H8300_ITU_CH
+ int "ITU channel"
+ depends on H8300_ITU
-config CPU_H8S
- bool
- depends on H8S2678
- default y
+config H8300_TPU_CH
+ int "TPU channel"
+ depends on H8300_TPU
config PREEMPT
bool "Preemptible Kernel"
diff --git a/arch/h8300/include/asm/bug.h b/arch/h8300/include/asm/bug.h
index edddf5b086e..887c1977318 100644
--- a/arch/h8300/include/asm/bug.h
+++ b/arch/h8300/include/asm/bug.h
@@ -1,4 +1,8 @@
#ifndef _H8300_BUG_H
#define _H8300_BUG_H
+
+/* always true */
+#define is_valid_bugaddr(addr) (1)
+
#include <asm-generic/bug.h>
#endif
diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h
index 26dc6ccd944..33e842f3284 100644
--- a/arch/h8300/include/asm/io.h
+++ b/arch/h8300/include/asm/io.h
@@ -295,6 +295,40 @@ static __inline__ void ctrl_outl(unsigned long b, unsigned long addr)
*(volatile unsigned long*)addr = b;
}
+static __inline__ void ctrl_bclr(int b, unsigned long addr)
+{
+ if (__builtin_constant_p(b))
+ switch (b) {
+ case 0: __asm__("bclr #0,@%0"::"r"(addr)); break;
+ case 1: __asm__("bclr #1,@%0"::"r"(addr)); break;
+ case 2: __asm__("bclr #2,@%0"::"r"(addr)); break;
+ case 3: __asm__("bclr #3,@%0"::"r"(addr)); break;
+ case 4: __asm__("bclr #4,@%0"::"r"(addr)); break;
+ case 5: __asm__("bclr #5,@%0"::"r"(addr)); break;
+ case 6: __asm__("bclr #6,@%0"::"r"(addr)); break;
+ case 7: __asm__("bclr #7,@%0"::"r"(addr)); break;
+ }
+ else
+ __asm__("bclr %w0,@%1"::"r"(b), "r"(addr));
+}
+
+static __inline__ void ctrl_bset(int b, unsigned long addr)
+{
+ if (__builtin_constant_p(b))
+ switch (b) {
+ case 0: __asm__("bset #0,@%0"::"r"(addr)); break;
+ case 1: __asm__("bset #1,@%0"::"r"(addr)); break;
+ case 2: __asm__("bset #2,@%0"::"r"(addr)); break;
+ case 3: __asm__("bset #3,@%0"::"r"(addr)); break;
+ case 4: __asm__("bset #4,@%0"::"r"(addr)); break;
+ case 5: __asm__("bset #5,@%0"::"r"(addr)); break;
+ case 6: __asm__("bset #6,@%0"::"r"(addr)); break;
+ case 7: __asm__("bset #7,@%0"::"r"(addr)); break;
+ }
+ else
+ __asm__("bset %w0,@%1"::"r"(b), "r"(addr));
+}
+
/* Pages to physical address... */
#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
#define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT)
diff --git a/arch/h8300/include/asm/md.h b/arch/h8300/include/asm/md.h
index 1a47dc6691f..1b7300e0a17 100644
--- a/arch/h8300/include/asm/md.h
+++ b/arch/h8300/include/asm/md.h
@@ -1,4 +1,4 @@
-/* $Id: md.h,v 1.1 2002/11/19 02:09:26 gerg Exp $
+/*
* md.h: High speed xor_block operation for RAID4/5
*
*/
diff --git a/arch/h8300/include/asm/system.h b/arch/h8300/include/asm/system.h
index 4b8e475908a..d98d97685f0 100644
--- a/arch/h8300/include/asm/system.h
+++ b/arch/h8300/include/asm/system.h
@@ -155,4 +155,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int siz
#define arch_align_stack(x) (x)
+void die(char *str, struct pt_regs *fp, unsigned long err);
+
#endif /* _H8300_SYSTEM_H */
diff --git a/arch/h8300/kernel/Makefile b/arch/h8300/kernel/Makefile
index 6c248c3c5c3..8d4d2a54be9 100644
--- a/arch/h8300/kernel/Makefile
+++ b/arch/h8300/kernel/Makefile
@@ -7,6 +7,6 @@ extra-y := vmlinux.lds
obj-y := process.o traps.o ptrace.o irq.o \
sys_h8300.o time.o signal.o \
setup.o gpio.o init_task.o syscalls.o \
- entry.o
+ entry.o timer/
obj-$(CONFIG_MODULES) += module.o h8300_ksyms.o
diff --git a/arch/h8300/kernel/module.c b/arch/h8300/kernel/module.c
index 4fd7138a6e0..cfc9127d2ce 100644
--- a/arch/h8300/kernel/module.c
+++ b/arch/h8300/kernel/module.c
@@ -114,9 +114,10 @@ int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
struct module *me)
{
- return 0;
+ return module_bug_finalize(hdr, sechdrs, me);
}
void module_arch_cleanup(struct module *mod)
{
+ module_bug_cleanup(mod);
}
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index e37c835e67c..7f2d6cfbb4b 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -27,27 +27,21 @@
#include <linux/profile.h>
#include <asm/io.h>
-#include <asm/target_time.h>
+#include <asm/timer.h>
#define TICK_SIZE (tick_nsec / 1000)
-/*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
- */
-static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
+void h8300_timer_tick(void)
{
- /* may need to kick the hardware timer */
- platform_timer_eoi();
-
+ if (current->pid)
+ profile_tick(CPU_PROFILING);
+ write_seqlock(&xtime_lock);
do_timer(1);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
-#endif
- profile_tick(CPU_PROFILING);
+ write_sequnlock(&xtime_lock);
+ update_process_times(user_mode(get_irq_regs()));
}
-void time_init(void)
+void __init time_init(void)
{
unsigned int year, mon, day, hour, min, sec;
@@ -57,12 +51,13 @@ void time_init(void)
year = 1980;
mon = day = 1;
hour = min = sec = 0;
- platform_gettod (&year, &mon, &day, &hour, &min, &sec);
-
+#ifdef CONFIG_H8300_GETTOD
+ h8300_gettod (&year, &mon, &day, &hour, &min, &sec);
+#endif
if ((year += 1900) < 1970)
year += 100;
xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
xtime.tv_nsec = 0;
- platform_timer_setup(timer_interrupt);
+ h8300_timer_setup();
}
diff --git a/arch/h8300/kernel/timer/Makefile b/arch/h8300/kernel/timer/Makefile
new file mode 100644
index 00000000000..bef0510ea6a
--- /dev/null
+++ b/arch/h8300/kernel/timer/Makefile
@@ -0,0 +1,6 @@
+# h8300 internal timer handler
+
+obj-$(CONFIG_H8300_TIMER8) := timer8.o
+obj-$(CONFIG_H8300_TIMER16) := timer16.o
+obj-$(CONFIG_H8300_ITU) := itu.o
+obj-$(CONFIG_H8300_TPU) := tpu.o
diff --git a/arch/h8300/kernel/timer/itu.c b/arch/h8300/kernel/timer/itu.c
new file mode 100644
index 00000000000..d1c926596b0
--- /dev/null
+++ b/arch/h8300/kernel/timer/itu.c
@@ -0,0 +1,83 @@
+/*
+ * linux/arch/h8300/kernel/timer/itu.c
+ *
+ * Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ * ITU Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs306x.h>
+
+#if CONFIG_H8300_ITU_CH == 0
+#define ITUBASE 0xffff64
+#define ITUIRQ 24
+#elif CONFIG_H8300_ITU_CH == 1
+#define ITUBASE 0xffff6e
+#define ITUIRQ 28
+#elif CONFIG_H8300_ITU_CH == 2
+#define ITUBASE 0xffff78
+#define ITUIRQ 32
+#elif CONFIG_H8300_ITU_CH == 3
+#define ITUBASE 0xffff82
+#define ITUIRQ 36
+#elif CONFIG_H8300_ITU_CH == 4
+#define ITUBASE 0xffff92
+#define ITUIRQ 40
+#else
+#error Unknown timer channel.
+#endif
+
+#define TCR 0
+#define TIOR 1
+#define TIER 2
+#define TSR 3
+#define TCNT 4
+#define GRA 6
+#define GRB 8
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ h8300_timer_tick();
+ ctrl_bclr(IMFA, ITUBASE + TSR);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction itu_irq = {
+ .name = "itu",
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .mask = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {1, 2, 4, 8};
+
+void __init h8300_timer_setup(void)
+{
+ unsigned int div;
+ unsigned int cnt;
+
+ calc_param(cnt, div, divide_rate, 0x10000);
+
+ setup_irq(ITUIRQ, &itu_irq);
+
+ /* initalize timer */
+ ctrl_outb(0, TSTR);
+ ctrl_outb(CCLR0 | div, ITUBASE + TCR);
+ ctrl_outb(0x01, ITUBASE + TIER);
+ ctrl_outw(cnt, ITUBASE + GRA);
+ ctrl_bset(CONFIG_H8300_ITU_CH, TSTR);
+}
diff --git a/arch/h8300/kernel/timer/timer16.c b/arch/h8300/kernel/timer/timer16.c
new file mode 100644
index 00000000000..e14271b7211
--- /dev/null
+++ b/arch/h8300/kernel/timer/timer16.c
@@ -0,0 +1,78 @@
+/*
+ * linux/arch/h8300/kernel/timer/timer16.c
+ *
+ * Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ * 16bit Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs306x.h>
+
+/* 16bit timer */
+#if CONFIG_H8300_TIMER16_CH == 0
+#define _16BASE 0xffff78
+#define _16IRQ 24
+#elif CONFIG_H8300_TIMER16_CH == 1
+#define _16BASE 0xffff80
+#define _16IRQ 28
+#elif CONFIG_H8300_TIMER16_CH == 2
+#define _16BASE 0xffff88
+#define _16IRQ 32
+#else
+#error Unknown timer channel.
+#endif
+
+#define TCR 0
+#define TIOR 1
+#define TCNT 2
+#define GRA 4
+#define GRB 6
+
+#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*10000 /* Timer input freq. */
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ h8300_timer_tick();
+ ctrl_bclr(CONFIG_H8300_TIMER16_CH, TISRA);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction timer16_irq = {
+ .name = "timer-16",
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .mask = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {1, 2, 4, 8};
+
+void __init h8300_timer_setup(void)
+{
+ unsigned int div;
+ unsigned int cnt;
+
+ calc_param(cnt, div, divide_rate, 0x10000);
+
+ setup_irq(_16IRQ, &timer16_irq);
+
+ /* initalize timer */
+ ctrl_outb(0, TSTR);
+ ctrl_outb(CCLR0 | div, _16BASE + TCR);
+ ctrl_outw(cnt, _16BASE + GRA);
+ ctrl_bset(4 + CONFIG_H8300_TIMER16_CH, TISRA);
+ ctrl_bset(CONFIG_H8300_TIMER16_CH, TSTR);
+}
diff --git a/arch/h8300/kernel/timer/timer8.c b/arch/h8300/kernel/timer/timer8.c
new file mode 100644
index 00000000000..0556d7c7bea
--- /dev/null
+++ b/arch/h8300/kernel/timer/timer8.c
@@ -0,0 +1,103 @@
+/*
+ * linux/arch/h8300/kernel/cpu/timer/timer8.c
+ *
+ * Yoshinori Sato <ysato@users.sourcefoge.jp>
+ *
+ * 8bit Timer Handler
+ *
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/profile.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/timer.h>
+#if defined(CONFIG_CPU_H8300H)
+#include <asm/regs306x.h>
+#endif
+#if defined(CONFIG_CPU_H8S)
+#include <asm/regs267x.h>
+#endif
+
+/* 8bit timer x2 */
+#define CMFA 6
+
+#if defined(CONFIG_H8300_TIMER8_CH0)
+#define _8BASE _8TCR0
+#ifdef CONFIG_CPU_H8300H
+#define _8IRQ 36
+#endif
+#ifdef CONFIG_CPU_H8S
+#define _8IRQ 72
+#endif
+#elif defined(CONFIG_H8300_TIMER8_CH2)
+#ifdef CONFIG_CPU_H8300H
+#define _8BASE _8TCR2
+#define _8IRQ 40
+#endif
+#endif
+
+#ifndef _8BASE
+#error Unknown timer channel.
+#endif
+
+#define _8TCR 0
+#define _8TCSR 2
+#define TCORA 4
+#define TCORB 6
+#define _8TCNT 8
+
+#define CMIEA 0x40
+#define CCLR_CMA 0x08
+#define CKS2 0x04
+
+/*
+ * timer_interrupt() needs to keep up the real-time clock,
+ * as well as call the "do_timer()" routine every clocktick
+ */
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ h8300_timer_tick();
+ ctrl_bclr(CMFA, _8BASE + _8TCSR);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction timer8_irq = {
+ .name = "timer-8",
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .mask = CPU_MASK_NONE,
+};
+
+static const int __initdata divide_rate[] = {8, 64, 8192};
+
+void __init h8300_timer_setup(void)
+{
+ unsigned int div;
+ unsigned int cnt;
+
+ calc_param(cnt, div, divide_rate, 0x10000);
+ div++;
+
+ setup_irq(_8IRQ, &timer8_irq);
+
+#if defined(CONFIG_CPU_H8S)
+ /* Timer module enable */
+ ctrl_bclr(0, MSTPCRL)
+#endif
+
+ /* initalize timer */
+ ctrl_outw(cnt, _8BASE + TCORA);
+ ctrl_outw(0x0000, _8BASE + _8TCSR);
+ ctrl_outw((CMIEA|CCLR_CMA|CKS2) << 8 | div,
+ _8BASE + _8TCR);
+}
diff --git a/arch/h8300/kernel/timer/tpu.c b/arch/h8300/kernel/timer/tpu.c
new file mode 100644
index 00000000000..df7f453a967
--- /dev/null
+++ b/arch/h8300/kernel/timer/tpu.c
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/h8300/kernel/timer/tpu.c
+ *
+ * Yoshinori Sato <ysato@users.sourceforge.jp>
+ *
+ * TPU Timer Handler
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/regs267x.h>
+
+/* TPU */
+#if CONFIG_H8300_TPU_CH == 0
+#define TPUBASE 0xffffd0
+#define TPUIRQ 40
+#elif CONFIG_H8300_TPU_CH == 1
+#define TPUBASE 0xffffe0
+#define TPUIRQ 48
+#elif CONFIG_H8300_TPU_CH == 2
+#define TPUBASE 0xfffff0
+#define TPUIRQ 52
+#elif CONFIG_H8300_TPU_CH == 3
+#define TPUBASE 0xfffe80
+#define TPUIRQ 56
+#elif CONFIG_H8300_TPU_CH == 4
+#define TPUBASE 0xfffe90
+#define TPUIRQ 64
+#else
+#error Unknown timer channel.
+#endif
+
+#define _TCR 0
+#define _TMDR 1
+#define _TIOR 2
+#define _TIER 4
+#define _TSR 5
+#define _TCNT 6
+#define _GRA 8
+#define _GRB 10
+
+#define CCLR0 0x20
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ h8300_timer_tick();
+ ctrl_bclr(0, TPUBASE + _TSR);
+ return IRQ_HANDLED;
+}
+
+static struct irqaction tpu_irq = {
+ .name = "tpu",
+ .handler = timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+ .mask = CPU_MASK_NONE,
+};
+
+const static int __initdata divide_rate[] = {
+#if CONFIG_H8300_TPU_CH == 0
+ 1,4,16,64,0,0,0,0,
+#elif (CONFIG_H8300_TPU_CH == 1) || (CONFIG_H8300_TPU_CH == 5)
+ 1,4,16,64,0,0,256,0,
+#elif (CONFIG_H8300_TPU_CH == 2) || (CONFIG_H8300_TPU_CH == 4)
+ 1,4,16,64,0,0,0,1024,
+#elif CONFIG_H8300_TPU_CH == 3
+ 1,4,16,64,0,1024,256,4096,
+#endif
+};
+
+void __init h8300_timer_setup(void)
+{
+ unsigned int cnt;
+ unsigned int div;
+
+ calc_param(cnt, div, divide_rate, 0x10000);
+
+ setup_irq(TPUIRQ, &tpu_irq);
+
+ /* TPU module enabled */
+ ctrl_bclr(3, MSTPCRH);
+
+ ctrl_outb(0, TSTR);
+ ctrl_outb(CCLR0 | div, TPUBASE + _TCR);
+ ctrl_outb(0, TPUBASE + _TMDR);
+ ctrl_outw(0, TPUBASE + _TIOR);
+ ctrl_outb(0x01, TPUBASE + _TIER);
+ ctrl_outw(cnt, TPUBASE + _GRA);
+ ctrl_bset(CONFIG_H8300_TPU_CH, TSTR);
+}
diff --git a/arch/h8300/kernel/traps.c b/arch/h8300/kernel/traps.c
index f8f7d7ea97f..3c0b66bc669 100644
--- a/arch/h8300/kernel/traps.c
+++ b/arch/h8300/kernel/traps.c
@@ -20,12 +20,14 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/bug.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/traps.h>
#include <asm/page.h>
-#include <asm/gpio.h>
+
+static DEFINE_SPINLOCK(die_lock);
/*
* this must be called very early as the kernel might
@@ -94,16 +96,19 @@ static void dump(struct pt_regs *fp)
printk("\n\n");
}
-void die_if_kernel (char *str, struct pt_regs *fp, int nr)
+void die(char *str, struct pt_regs *fp, unsigned long err)
{
- extern int console_loglevel;
+ static int diecount;
- if (!(fp->ccr & PS_S))
- return;
+ oops_enter();
- console_loglevel = 15;
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ report_bug(fp->pc, fp);
+ printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++diecount);
dump(fp);
+ spin_unlock_irq(&die_lock);
do_exit(SIGSEGV);
}
diff --git a/arch/h8300/mm/fault.c b/arch/h8300/mm/fault.c
index 29e9af9f0e6..1d092abebf0 100644
--- a/arch/h8300/mm/fault.c
+++ b/arch/h8300/mm/fault.c
@@ -20,8 +20,6 @@
#include <asm/system.h>
#include <asm/pgtable.h>
-extern void die_if_kernel(char *, struct pt_regs *, long);
-
/*
* This routine handles page faults. It determines the problem, and
* then passes it off to one of the appropriate routines.
@@ -50,7 +48,8 @@ asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
} else
printk(KERN_ALERT "Unable to handle kernel access");
printk(" at virtual address %08lx\n",address);
- die_if_kernel("Oops", regs, error_code);
+ if (!user_mode(regs))
+ die("Oops", regs, error_code);
do_exit(SIGKILL);
return 1;
diff --git a/arch/h8300/platform/h8300h/aki3068net/Makefile b/arch/h8300/platform/h8300h/aki3068net/Makefile
index b03c328f8c7..b7ff78050b7 100644
--- a/arch/h8300/platform/h8300h/aki3068net/Makefile
+++ b/arch/h8300/platform/h8300h/aki3068net/Makefile
@@ -3,4 +3,3 @@
#
extra-y := crt0_ram.o
-obj-y := timer.o
diff --git a/arch/h8300/platform/h8300h/aki3068net/timer.c b/arch/h8300/platform/h8300h/aki3068net/timer.c
deleted file mode 100644
index 27cd85d5612..00000000000
--- a/arch/h8300/platform/h8300h/aki3068net/timer.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/aki3068net/timer.c
- *
- * Yoshinori Sato <ysato@users.sourcefoge.jp>
- *
- * Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs306x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- /* setup 8bit timer ch2 */
- ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2); /* set interval */
- ctrl_outb(0x00, _8TCSR2); /* no output */
- request_irq(40, timer_int, 0, "timer", 0);
- ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
- *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
- int *min, int *sec)
-{
- *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8300h/generic/Makefile b/arch/h8300/platform/h8300h/generic/Makefile
index 32b964a9010..2b12a170209 100644
--- a/arch/h8300/platform/h8300h/generic/Makefile
+++ b/arch/h8300/platform/h8300h/generic/Makefile
@@ -3,4 +3,3 @@
#
extra-y := crt0_$(MODEL).o
-obj-y := timer.o
diff --git a/arch/h8300/platform/h8300h/generic/timer.c b/arch/h8300/platform/h8300h/generic/timer.c
deleted file mode 100644
index 6f5cefe0cce..00000000000
--- a/arch/h8300/platform/h8300h/generic/timer.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/generic/timer.c
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- * Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <linux/timex.h>
-
-#if defined(CONFIG_H83007) || defined(CONFIG_H83068)
-#include <asm/regs306x.h>
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- /* setup 8bit timer ch2 */
- ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2); /* set interval */
- ctrl_outb(0x00, _8TCSR2); /* no output */
- request_irq(40, timer_int, 0, "timer", 0);
- ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
- *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-#endif
-
-#if defined(CONFIG_H83002) || defined(CONFIG_H83048)
-/* FIXME! */
-#define TSTR 0x00ffff60
-#define TSNC 0x00ffff61
-#define TMDR 0x00ffff62
-#define TFCR 0x00ffff63
-#define TOER 0x00ffff90
-#define TOCR 0x00ffff91
-/* ITU0 */
-#define TCR 0x00ffff64
-#define TIOR 0x00ffff65
-#define TIER 0x00ffff66
-#define TSR 0x00ffff67
-#define TCNT 0x00ffff68
-#define GRA 0x00ffff6a
-#define GRB 0x00ffff6c
-
-#define CCLR_CMGRA 0x20
-#define CLK_DIV8 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- *(unsigned short *)GRA= H8300_TIMER_FREQ / HZ; /* set interval */
- *(unsigned short *)TCNT=0; /* clear counter */
- ctrl_outb(0x80|CCLR_CMGRA|CLK_DIV8, TCR); /* set ITU0 clock */
- ctrl_outb(0x88, TIOR); /* no output */
- request_irq(26, timer_int, 0, "timer", 0);
- ctrl_outb(0xf9, TIER); /* compare match GRA interrupt */
- ctrl_outb(ctrl_inb(TSNC) & ~0x01, TSNC); /* ITU0 async */
- ctrl_outb(ctrl_inb(TMDR) & ~0x01, TMDR); /* ITU0 normal mode */
- ctrl_outb(ctrl_inb(TSTR) | 0x01, TSTR); /* ITU0 Start */
- return 0;
-}
-
-void platform_timer_eoi(void)
-{
- ctrl_outb(ctrl_inb(TSR) & ~0x01,TSR);
-}
-#endif
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
- int *min, int *sec)
-{
- *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8300h/h8max/Makefile b/arch/h8300/platform/h8300h/h8max/Makefile
index b03c328f8c7..b7ff78050b7 100644
--- a/arch/h8300/platform/h8300h/h8max/Makefile
+++ b/arch/h8300/platform/h8300h/h8max/Makefile
@@ -3,4 +3,3 @@
#
extra-y := crt0_ram.o
-obj-y := timer.o
diff --git a/arch/h8300/platform/h8300h/h8max/timer.c b/arch/h8300/platform/h8300h/h8max/timer.c
deleted file mode 100644
index 85a574afe9d..00000000000
--- a/arch/h8300/platform/h8300h/h8max/timer.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8300h/h8max/timer.c
- *
- * Yoshinori Sato <ysato@users.sourcefoge.jp>
- *
- * Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs306x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- /* setup 8bit timer ch2 */
- ctrl_outb(H8300_TIMER_FREQ / HZ, TCORA2); /* set interval */
- ctrl_outb(0x00, _8TCSR2); /* no output */
- request_irq(40, timer_int, 0, "timer", 0);
- ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR2); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
- *(volatile unsigned char *)_8TCSR2 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
- int *min, int *sec)
-{
- *year = *mon = *day = *hour = *min = *sec = 0;
-}
-
diff --git a/arch/h8300/platform/h8s/edosk2674/Makefile b/arch/h8300/platform/h8s/edosk2674/Makefile
index f763654ac6f..8e349723bb4 100644
--- a/arch/h8300/platform/h8s/edosk2674/Makefile
+++ b/arch/h8300/platform/h8s/edosk2674/Makefile
@@ -3,4 +3,3 @@
#
extra-y := crt0_$(MODEL).o
-obj-y := timer.o
diff --git a/arch/h8300/platform/h8s/edosk2674/timer.c b/arch/h8300/platform/h8s/edosk2674/timer.c
deleted file mode 100644
index bfb1424482f..00000000000
--- a/arch/h8300/platform/h8s/edosk2674/timer.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8s/edosk2674/timer.c
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- * Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs267x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- /* 8bit timer module enabled */
- ctrl_outb(ctrl_inb(MSTPCRL) & ~0x01, MSTPCRL);
- /* setup 8bit timer ch1 */
- ctrl_outb(H8300_TIMER_FREQ / HZ, _8TCORA1); /* set interval */
- ctrl_outb(0x00, _8TCSR1); /* no output */
- request_irq(76, timer_int, 0, "timer" ,0);
- ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR1); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
- *(volatile unsigned char *)_8TCSR1 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
- int *min, int *sec)
-{
-/* FIXME! not RTC support */
- *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/h8300/platform/h8s/generic/Makefile b/arch/h8300/platform/h8s/generic/Makefile
index 055d53a9811..44b4685c664 100644
--- a/arch/h8300/platform/h8s/generic/Makefile
+++ b/arch/h8300/platform/h8s/generic/Makefile
@@ -3,4 +3,3 @@
#
extra-y = crt0_$(MODEL).o
-obj-y := timer.o
diff --git a/arch/h8300/platform/h8s/generic/timer.c b/arch/h8300/platform/h8s/generic/timer.c
deleted file mode 100644
index c2211c6e79d..00000000000
--- a/arch/h8300/platform/h8s/generic/timer.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * linux/arch/h8300/platform/h8s/generic/timer.c
- *
- * Yoshinori Sato <ysato@users.sourceforge.jp>
- *
- * Platform depend Timer Handler
- *
- */
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/regs267x.h>
-
-#define CMFA 6
-
-#define CMIEA 0x40
-#define CCLR_CMA 0x08
-#define CLK_DIV8192 0x03
-
-#define H8300_TIMER_FREQ CONFIG_CPU_CLOCK*1000/8192 /* Timer input freq. */
-
-void __init platform_timer_setup(irqreturn_t (*timer_int)(int, void *, struct pt_regs *))
-{
- /* 8bit timer module enabled */
- ctrl_outb(ctrl_inb(MSTPCRL) & ~0x01, MSTPCRL);
- /* setup 8bit timer ch1 */
- ctrl_outb(H8300_TIMER_FREQ / HZ, _8TCORA1); /* set interval */
- ctrl_outb(0x00, _8TCSR1); /* no output */
- request_irq(76, timer_int, 0, "timer" ,0);
- ctrl_outb(CMIEA|CCLR_CMA|CLK_DIV8192, _8TCR1); /* start count */
-}
-
-void platform_timer_eoi(void)
-{
- *(volatile unsigned char *)_8TCSR1 &= ~(1 << CMFA);
-}
-
-void platform_gettod(int *year, int *mon, int *day, int *hour,
- int *min, int *sec)
-{
- *year = *mon = *day = *hour = *min = *sec = 0;
-}
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 48e496fe1e7..3b7aa38254a 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -60,14 +60,6 @@ config RWSEM_XCHGADD_ALGORITHM
bool
default y
-config ARCH_HAS_ILOG2_U32
- bool
- default n
-
-config ARCH_HAS_ILOG2_U64
- bool
- default n
-
config HUGETLB_PAGE_SIZE_VARIABLE
bool
depends on HUGETLB_PAGE
diff --git a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
index ff88c48c5d1..53505bb0477 100644
--- a/arch/ia64/ia32/ia32_entry.S
+++ b/arch/ia64/ia32/ia32_entry.S
@@ -251,8 +251,8 @@ ia32_syscall_table:
data8 compat_sys_setrlimit /* 75 */
data8 compat_sys_old_getrlimit
data8 compat_sys_getrusage
- data8 sys32_gettimeofday
- data8 sys32_settimeofday
+ data8 compat_sys_gettimeofday
+ data8 compat_sys_settimeofday
data8 sys32_getgroups16 /* 80 */
data8 sys32_setgroups16
data8 sys32_old_select
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index bf196cbb379..f4430bb4bbd 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -118,41 +118,6 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use
return error;
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
-{
- compat_ino_t ino;
- int err;
-
- if ((u64) stat->size > MAX_NON_LFS ||
- !old_valid_dev(stat->dev) ||
- !old_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- ino = stat->ino;
- if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
- return -EOVERFLOW;
-
- if (clear_user(ubuf, sizeof(*ubuf)))
- return -EFAULT;
-
- err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
- err |= __put_user(ino, &ubuf->st_ino);
- err |= __put_user(stat->mode, &ubuf->st_mode);
- err |= __put_user(stat->nlink, &ubuf->st_nlink);
- err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
- err |= __put_user(high2lowgid(stat->gid), &ubuf->st_gid);
- err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
- err |= __put_user(stat->size, &ubuf->st_size);
- err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
- err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
- err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
- err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
- err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
- err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
- err |= __put_user(stat->blksize, &ubuf->st_blksize);
- err |= __put_user(stat->blocks, &ubuf->st_blocks);
- return err;
-}
#if PAGE_SHIFT > IA32_PAGE_SHIFT
@@ -1148,68 +1113,12 @@ sys32_pipe (int __user *fd)
return retval;
}
-static inline long
-get_tv32 (struct timeval *o, struct compat_timeval __user *i)
-{
- return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
- (__get_user(o->tv_sec, &i->tv_sec) | __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long
-put_tv32 (struct compat_timeval __user *o, struct timeval *i)
-{
- return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
- (__put_user(i->tv_sec, &o->tv_sec) | __put_user(i->tv_usec, &o->tv_usec)));
-}
-
asmlinkage unsigned long
sys32_alarm (unsigned int seconds)
{
return alarm_setitimer(seconds);
}
-/* Translations due to time_t size differences. Which affects all
- sorts of things, like timeval and itimerval. */
-
-extern struct timezone sys_tz;
-
-asmlinkage long
-sys32_gettimeofday (struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage long
-sys32_settimeofday (struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- struct timeval ktv;
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_tv32(&ktv, tv))
- return -EFAULT;
- kts.tv_sec = ktv.tv_sec;
- kts.tv_nsec = ktv.tv_usec * 1000;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
struct sel_arg_struct {
unsigned int n;
unsigned int inp;
diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c
index 5be4faaf5b1..7103d91e1a2 100644
--- a/arch/m32r/kernel/process.c
+++ b/arch/m32r/kernel/process.c
@@ -11,7 +11,7 @@
#undef DEBUG_PROCESS
#ifdef DEBUG_PROCESS
#define DPRINTK(fmt, args...) printk("%s:%d:%s: " fmt, __FILE__, __LINE__, \
- __FUNCTION__, ##args)
+ __func__, ##args)
#else
#define DPRINTK(fmt, args...)
#endif
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 41e5bf02e23..677c93a490f 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -105,21 +105,9 @@ config PCMCIA
To compile this driver as modules, choose M here: the
modules will be called pcmcia_core and ds.
-config SUN3
- bool "Sun3 support"
- select M68020
- select MMU_SUN3 if MMU
- help
- This option enables support for the Sun 3 series of workstations
- (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
- that all other hardware types must be disabled, as Sun 3 kernels
- are incompatible with all other m68k targets (including Sun 3x!).
-
- If you don't want to compile a kernel exclusively for a Sun 3, say N.
-
config AMIGA
bool "Amiga support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
This option enables support for the Amiga series of computers. If
you plan to use this kernel on an Amiga, say Y here and browse the
@@ -127,33 +115,16 @@ config AMIGA
config ATARI
bool "Atari support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
This option enables support for the 68000-based Atari series of
computers (including the TT, Falcon and Medusa). If you plan to use
this kernel on an Atari, say Y here and browse the material
available in <file:Documentation/m68k>; otherwise say N.
-config HADES
- bool "Hades support"
- depends on ATARI && BROKEN
- help
- This option enables support for the Hades Atari clone. If you plan
- to use this kernel on a Hades, say Y here; otherwise say N.
-
-config PCI
- bool
- depends on HADES
- default y
- help
- Find out whether you have a PCI motherboard. PCI is the name of a
- bus system, i.e. the way the CPU talks to the other stuff inside
- your box. Other bus systems are ISA, EISA, MicroChannel (MCA) or
- VESA. If you have PCI, say Y, otherwise N.
-
config MAC
bool "Macintosh support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
This option enables support for the Apple Macintosh series of
computers (yes, there is experimental support now, at least for part
@@ -174,14 +145,14 @@ config M68K_L2_CACHE
config APOLLO
bool "Apollo support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
Say Y here if you want to run Linux on an MC680x0-based Apollo
Domain workstation such as the DN3500.
config VME
bool "VME (Motorola and BVM) support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
Say Y here if you want to build a kernel for a 680x0 based VME
board. Boards currently supported include Motorola boards MVME147,
@@ -218,7 +189,7 @@ config BVME6000
config HP300
bool "HP9000/300 and HP9000/400 support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
This option enables support for the HP9000/300 and HP9000/400 series
of workstations. Support for these machines is still somewhat
@@ -237,7 +208,7 @@ config DIO
config SUN3X
bool "Sun3x support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
select M68030
help
This option enables support for the Sun 3x series of workstations.
@@ -250,7 +221,7 @@ config SUN3X
config Q40
bool "Q40/Q60 support"
- depends on !MMU_SUN3
+ select MMU_MOTOROLA if MMU
help
The Q40 is a Motorola 68040-based successor to the Sinclair QL
manufactured in Germany. There is an official Q40 home page at
@@ -258,6 +229,19 @@ config Q40
Q60. Select your CPU below. For 68LC060 don't forget to enable FPU
emulation.
+config SUN3
+ bool "Sun3 support"
+ depends on !MMU_MOTOROLA
+ select MMU_SUN3 if MMU
+ select M68020
+ help
+ This option enables support for the Sun 3 series of workstations
+ (3/50, 3/60, 3/1xx, 3/2xx systems). Enabling this option requires
+ that all other hardware types must be disabled, as Sun 3 kernels
+ are incompatible with all other m68k targets (including Sun 3x!).
+
+ If you don't want to compile a kernel exclusively for a Sun 3, say N.
+
comment "Processor type"
config M68020
@@ -295,10 +279,10 @@ config M68060
config MMU_MOTOROLA
bool
depends on MMU && !MMU_SUN3
- default y
config MMU_SUN3
bool
+ depends on MMU && !MMU_MOTOROLA
config M68KFPU_EMU
bool "Math emulation support (EXPERIMENTAL)"
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index df679d96b1c..0a3f9e8ebde 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/zorro.h>
#include <linux/module.h>
+#include <linux/keyboard.h>
#include <asm/bootinfo.h>
#include <asm/setup.h>
@@ -984,3 +985,11 @@ static int amiga_get_hardware_list(char *buffer)
return len;
}
+
+/*
+ * The Amiga keyboard driver needs key_maps, but we cannot export it in
+ * drivers/char/defkeymap.c, as it is autogenerated
+ */
+#ifdef CONFIG_HW_CONSOLE
+EXPORT_SYMBOL_GPL(key_maps);
+#endif
diff --git a/arch/m68k/atari/Makefile b/arch/m68k/atari/Makefile
index 2cd905efe63..0cac723306f 100644
--- a/arch/m68k/atari/Makefile
+++ b/arch/m68k/atari/Makefile
@@ -5,7 +5,4 @@
obj-y := config.o time.o debug.o ataints.o stdma.o \
atasound.o stram.o
-ifeq ($(CONFIG_PCI),y)
-obj-$(CONFIG_HADES) += hades-pci.o
-endif
obj-$(CONFIG_ATARI_KBD_CORE) += atakeyb.o
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index b45593a60bd..dba4afabb44 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -407,10 +407,8 @@ void __init atari_init_IRQ(void)
* gets overruns)
*/
- if (!MACH_IS_HADES) {
- vectors[VEC_INT2] = falcon_hblhandler;
- vectors[VEC_INT4] = falcon_hblhandler;
- }
+ vectors[VEC_INT2] = falcon_hblhandler;
+ vectors[VEC_INT4] = falcon_hblhandler;
}
if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c
index bb959fbab2d..c038b7c7eff 100644
--- a/arch/m68k/atari/atakeyb.c
+++ b/arch/m68k/atari/atakeyb.c
@@ -635,15 +635,3 @@ int atari_keyb_init(void)
return 0;
}
EXPORT_SYMBOL_GPL(atari_keyb_init);
-
-int atari_kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode)
-{
-#ifdef CONFIG_MAGIC_SYSRQ
- /* ALT+HELP pressed? */
- if ((keycode == 98) && ((shift_state & 0xff) == 8))
- *keycodep = 0xff;
- else
-#endif
- *keycodep = keycode;
- return 1;
-}
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 5945e150555..af031855f79 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -231,7 +231,7 @@ void __init config_atari(void)
*/
printk("Atari hardware found: ");
- if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+ if (MACH_IS_MEDUSA) {
/* There's no Atari video hardware on the Medusa, but all the
* addresses below generate a DTACK so no bus error occurs! */
} else if (hwreg_present(f030_xreg)) {
@@ -269,10 +269,6 @@ void __init config_atari(void)
ATARIHW_SET(SCSI_DMA);
printk("TT_SCSI_DMA ");
}
- if (!MACH_IS_HADES && hwreg_present(&st_dma.dma_hi)) {
- ATARIHW_SET(STND_DMA);
- printk("STND_DMA ");
- }
/*
* The ST-DMA address registers aren't readable
* on all Medusas, so the test below may fail
@@ -294,12 +290,11 @@ void __init config_atari(void)
ATARIHW_SET(YM_2149);
printk("YM2149 ");
}
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present(&tt_dmasnd.ctrl)) {
+ if (!MACH_IS_MEDUSA && hwreg_present(&tt_dmasnd.ctrl)) {
ATARIHW_SET(PCM_8BIT);
printk("PCM ");
}
- if (!MACH_IS_HADES && hwreg_present(&falcon_codec.unused5)) {
+ if (hwreg_present(&falcon_codec.unused5)) {
ATARIHW_SET(CODEC);
printk("CODEC ");
}
@@ -313,7 +308,7 @@ void __init config_atari(void)
(tt_scc_dma.dma_ctrl = 0x01, (tt_scc_dma.dma_ctrl & 1) == 1) &&
(tt_scc_dma.dma_ctrl = 0x00, (tt_scc_dma.dma_ctrl & 1) == 0)
#else
- !MACH_IS_MEDUSA && !MACH_IS_HADES
+ !MACH_IS_MEDUSA
#endif
) {
ATARIHW_SET(SCC_DMA);
@@ -327,10 +322,7 @@ void __init config_atari(void)
ATARIHW_SET(ST_ESCC);
printk("ST_ESCC ");
}
- if (MACH_IS_HADES) {
- ATARIHW_SET(VME);
- printk("VME ");
- } else if (hwreg_present(&tt_scu.sys_mask)) {
+ if (hwreg_present(&tt_scu.sys_mask)) {
ATARIHW_SET(SCU);
/* Assume a VME bus if there's a SCU */
ATARIHW_SET(VME);
@@ -340,7 +332,7 @@ void __init config_atari(void)
ATARIHW_SET(ANALOG_JOY);
printk("ANALOG_JOY ");
}
- if (!MACH_IS_HADES && hwreg_present(blitter.halftone)) {
+ if (hwreg_present(blitter.halftone)) {
ATARIHW_SET(BLITTER);
printk("BLITTER ");
}
@@ -349,8 +341,7 @@ void __init config_atari(void)
printk("IDE ");
}
#if 1 /* This maybe wrong */
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present(&tt_microwire.data) &&
+ if (!MACH_IS_MEDUSA && hwreg_present(&tt_microwire.data) &&
hwreg_present(&tt_microwire.mask) &&
(tt_microwire.mask = 0x7ff,
udelay(1),
@@ -369,19 +360,18 @@ void __init config_atari(void)
mach_hwclk = atari_tt_hwclk;
mach_set_clock_mmss = atari_tt_set_clock_mmss;
}
- if (!MACH_IS_HADES && hwreg_present(&mste_rtc.sec_ones)) {
+ if (hwreg_present(&mste_rtc.sec_ones)) {
ATARIHW_SET(MSTE_CLK);
printk("MSTE_CLK ");
mach_hwclk = atari_mste_hwclk;
mach_set_clock_mmss = atari_mste_set_clock_mmss;
}
- if (!MACH_IS_MEDUSA && !MACH_IS_HADES &&
- hwreg_present(&dma_wd.fdc_speed) &&
+ if (!MACH_IS_MEDUSA && hwreg_present(&dma_wd.fdc_speed) &&
hwreg_write(&dma_wd.fdc_speed, 0)) {
ATARIHW_SET(FDCSPEED);
printk("FDC_SPEED ");
}
- if (!MACH_IS_HADES && !ATARIHW_PRESENT(ST_SCSI)) {
+ if (!ATARIHW_PRESENT(ST_SCSI)) {
ATARIHW_SET(ACSI);
printk("ACSI ");
}
@@ -449,7 +439,7 @@ void __init config_atari(void)
* 0xFFxxxxxx -> 0x00xxxxxx, so that the first 16MB is accessible
* in the last 16MB of the address space.
*/
- tos_version = (MACH_IS_MEDUSA || MACH_IS_HADES) ?
+ tos_version = (MACH_IS_MEDUSA) ?
0xfff : *(unsigned short *)0xff000002;
atari_rtc_year_offset = (tos_version < 0x306) ? 70 : 68;
}
@@ -511,8 +501,7 @@ static void atari_reset(void)
* On the Medusa, phys. 0x4 may contain garbage because it's no
* ROM. See above for explanation why we cannot use PTOV(4).
*/
- reset_addr = MACH_IS_HADES ? 0x7fe00030 :
- MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
+ reset_addr = MACH_IS_MEDUSA || MACH_IS_AB40 ? 0xe00030 :
*(unsigned long *) 0xff000004;
/* reset ACIA for switch off OverScan, if it's active */
@@ -606,8 +595,6 @@ static void atari_get_model(char *model)
if (MACH_IS_MEDUSA)
/* Medusa has TT _MCH cookie */
strcat(model, "Medusa");
- else if (MACH_IS_HADES)
- strcat(model, "Hades");
else
strcat(model, "TT");
break;
diff --git a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c
deleted file mode 100644
index 2bbabc00870..00000000000
--- a/arch/m68k/atari/hades-pci.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * hades-pci.c - Hardware specific PCI BIOS functions the Hades Atari clone.
- *
- * Written by Wout Klaren.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/io.h>
-
-#if 0
-# define DBG_DEVS(args) printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#if defined(CONFIG_PCI) && defined(CONFIG_HADES)
-
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/atarihw.h>
-#include <asm/atariints.h>
-#include <asm/byteorder.h>
-#include <asm/pci.h>
-
-#define HADES_MEM_BASE 0x80000000
-#define HADES_MEM_SIZE 0x20000000
-#define HADES_CONFIG_BASE 0xA0000000
-#define HADES_CONFIG_SIZE 0x10000000
-#define HADES_IO_BASE 0xB0000000
-#define HADES_IO_SIZE 0x10000000
-#define HADES_VIRT_IO_SIZE 0x00010000 /* Only 64k is remapped and actually used. */
-
-#define N_SLOTS 4 /* Number of PCI slots. */
-
-static const char pci_mem_name[] = "PCI memory space";
-static const char pci_io_name[] = "PCI I/O space";
-static const char pci_config_name[] = "PCI config space";
-
-static struct resource config_space = {
- .name = pci_config_name,
- .start = HADES_CONFIG_BASE,
- .end = HADES_CONFIG_BASE + HADES_CONFIG_SIZE - 1
-};
-static struct resource io_space = {
- .name = pci_io_name,
- .start = HADES_IO_BASE,
- .end = HADES_IO_BASE + HADES_IO_SIZE - 1
-};
-
-static const unsigned long pci_conf_base_phys[] = {
- 0xA0080000, 0xA0040000, 0xA0020000, 0xA0010000
-};
-static unsigned long pci_conf_base_virt[N_SLOTS];
-static unsigned long pci_io_base_virt;
-
-/*
- * static void *mk_conf_addr(unsigned char bus, unsigned char device_fn,
- * unsigned char where)
- *
- * Calculate the address of the PCI configuration area of the given
- * device.
- *
- * BUG: boards with multiple functions are probably not correctly
- * supported.
- */
-
-static void *mk_conf_addr(struct pci_dev *dev, int where)
-{
- int device = dev->devfn >> 3, function = dev->devfn & 7;
- void *result;
-
- DBG_DEVS(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x, pci_addr=0x%p)\n",
- dev->bus->number, dev->devfn, where, pci_addr));
-
- if (device > 3)
- {
- DBG_DEVS(("mk_conf_addr: device (%d) > 3, returning NULL\n", device));
- return NULL;
- }
-
- if (dev->bus->number != 0)
- {
- DBG_DEVS(("mk_conf_addr: bus (%d) > 0, returning NULL\n", device));
- return NULL;
- }
-
- result = (void *) (pci_conf_base_virt[device] | (function << 8) | (where));
- DBG_DEVS(("mk_conf_addr: returning pci_addr 0x%lx\n", (unsigned long) result));
- return result;
-}
-
-static int hades_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
- volatile unsigned char *pci_addr;
-
- *value = 0xff;
-
- if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- *value = *pci_addr;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
- volatile unsigned short *pci_addr;
-
- *value = 0xffff;
-
- if (where & 0x1)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- *value = le16_to_cpu(*pci_addr);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
- volatile unsigned int *pci_addr;
- unsigned char header_type;
- int result;
-
- *value = 0xffffffff;
-
- if (where & 0x3)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- *value = le32_to_cpu(*pci_addr);
-
- /*
- * Check if the value is an address on the bus. If true, add the
- * base address of the PCI memory or PCI I/O area on the Hades.
- */
-
- if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
- &header_type)) != PCIBIOS_SUCCESSFUL)
- return result;
-
- if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
- ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
- (where <= PCI_BASE_ADDRESS_5))))
- {
- if ((*value & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
- {
- /*
- * Base address register that contains an I/O address. If the
- * address is valid on the Hades (0 <= *value < HADES_VIRT_IO_SIZE),
- * add 'pci_io_base_virt' to the value.
- */
-
- if (*value < HADES_VIRT_IO_SIZE)
- *value += pci_io_base_virt;
- }
- else
- {
- /*
- * Base address register that contains an memory address. If the
- * address is valid on the Hades (0 <= *value < HADES_MEM_SIZE),
- * add HADES_MEM_BASE to the value.
- */
-
- if (*value == 0)
- {
- /*
- * Base address is 0. Test if this base
- * address register is used.
- */
-
- *pci_addr = 0xffffffff;
- if (*pci_addr != 0)
- {
- *pci_addr = *value;
- if (*value < HADES_MEM_SIZE)
- *value += HADES_MEM_BASE;
- }
- }
- else
- {
- if (*value < HADES_MEM_SIZE)
- *value += HADES_MEM_BASE;
- }
- }
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
- volatile unsigned char *pci_addr;
-
- if ((pci_addr = (unsigned char *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- *pci_addr = value;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
- volatile unsigned short *pci_addr;
-
- if ((pci_addr = (unsigned short *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- *pci_addr = cpu_to_le16(value);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int hades_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
- volatile unsigned int *pci_addr;
- unsigned char header_type;
- int result;
-
- if ((pci_addr = (unsigned int *) mk_conf_addr(dev, where)) == NULL)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- /*
- * Check if the value is an address on the bus. If true, subtract the
- * base address of the PCI memory or PCI I/O area on the Hades.
- */
-
- if ((result = hades_read_config_byte(dev, PCI_HEADER_TYPE,
- &header_type)) != PCIBIOS_SUCCESSFUL)
- return result;
-
- if (((where >= PCI_BASE_ADDRESS_0) && (where <= PCI_BASE_ADDRESS_1)) ||
- ((header_type != PCI_HEADER_TYPE_BRIDGE) && ((where >= PCI_BASE_ADDRESS_2) &&
- (where <= PCI_BASE_ADDRESS_5))))
- {
- if ((value & PCI_BASE_ADDRESS_SPACE) ==
- PCI_BASE_ADDRESS_SPACE_IO)
- {
- /*
- * I/O address. Check if the address is valid address on
- * the Hades (pci_io_base_virt <= value < pci_io_base_virt +
- * HADES_VIRT_IO_SIZE) or if the value is 0xffffffff. If not
- * true do not write the base address register. If it is a
- * valid base address subtract 'pci_io_base_virt' from the value.
- */
-
- if ((value >= pci_io_base_virt) && (value < (pci_io_base_virt +
- HADES_VIRT_IO_SIZE)))
- value -= pci_io_base_virt;
- else
- {
- if (value != 0xffffffff)
- return PCIBIOS_SET_FAILED;
- }
- }
- else
- {
- /*
- * Memory address. Check if the address is valid address on
- * the Hades (HADES_MEM_BASE <= value < HADES_MEM_BASE + HADES_MEM_SIZE) or
- * if the value is 0xffffffff. If not true do not write
- * the base address register. If it is a valid base address
- * subtract HADES_MEM_BASE from the value.
- */
-
- if ((value >= HADES_MEM_BASE) && (value < (HADES_MEM_BASE + HADES_MEM_SIZE)))
- value -= HADES_MEM_BASE;
- else
- {
- if (value != 0xffffffff)
- return PCIBIOS_SET_FAILED;
- }
- }
- }
-
- *pci_addr = cpu_to_le32(value);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * static inline void hades_fixup(void)
- *
- * Assign IRQ numbers as used by Linux to the interrupt pins
- * of the PCI cards.
- */
-
-static void __init hades_fixup(int pci_modify)
-{
- char irq_tab[4] = {
- [0] = IRQ_TT_MFP_IO0, /* Slot 0. */
- [1] = IRQ_TT_MFP_IO1, /* Slot 1. */
- [2] = IRQ_TT_MFP_SCC, /* Slot 2. */
- [3] = IRQ_TT_MFP_SCSIDMA /* Slot 3. */
- };
- struct pci_dev *dev = NULL;
- unsigned char slot;
-
- /*
- * Go through all devices, fixing up irqs as we see fit:
- */
-
- while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL)
- {
- if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE)
- {
- slot = PCI_SLOT(dev->devfn); /* Determine slot number. */
- dev->irq = irq_tab[slot];
- if (pci_modify)
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
- }
-}
-
-/*
- * static void hades_conf_device(struct pci_dev *dev)
- *
- * Machine dependent Configure the given device.
- *
- * Parameters:
- *
- * dev - the pci device.
- */
-
-static void __init hades_conf_device(struct pci_dev *dev)
-{
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 0);
-}
-
-static struct pci_ops hades_pci_ops = {
- .read_byte = hades_read_config_byte,
- .read_word = hades_read_config_word,
- .read_dword = hades_read_config_dword,
- .write_byte = hades_write_config_byte,
- .write_word = hades_write_config_word,
- .write_dword = hades_write_config_dword
-};
-
-/*
- * struct pci_bus_info *init_hades_pci(void)
- *
- * Machine specific initialisation:
- *
- * - Allocate and initialise a 'pci_bus_info' structure
- * - Initialise hardware
- *
- * Result: pointer to 'pci_bus_info' structure.
- */
-
-struct pci_bus_info * __init init_hades_pci(void)
-{
- struct pci_bus_info *bus;
- int i;
-
- /*
- * Remap I/O and configuration space.
- */
-
- pci_io_base_virt = (unsigned long) ioremap(HADES_IO_BASE, HADES_VIRT_IO_SIZE);
-
- for (i = 0; i < N_SLOTS; i++)
- pci_conf_base_virt[i] = (unsigned long) ioremap(pci_conf_base_phys[i], 0x10000);
-
- /*
- * Allocate memory for bus info structure.
- */
-
- bus = kzalloc(sizeof(struct pci_bus_info), GFP_KERNEL);
- if (unlikely(!bus))
- goto iounmap_base_virt;
-
- /*
- * Claim resources. The m68k has no separate I/O space, both
- * PCI memory space and PCI I/O space are in memory space. Therefore
- * the I/O resources are requested in memory space as well.
- */
-
- if (unlikely(request_resource(&iomem_resource, &config_space) != 0))
- goto free_bus;
-
- if (unlikely(request_resource(&iomem_resource, &io_space) != 0))
- goto release_config_space;
-
- bus->mem_space.start = HADES_MEM_BASE;
- bus->mem_space.end = HADES_MEM_BASE + HADES_MEM_SIZE - 1;
- bus->mem_space.name = pci_mem_name;
-#if 1
- if (unlikely(request_resource(&iomem_resource, &bus->mem_space) != 0))
- goto release_io_space;
-#endif
- bus->io_space.start = pci_io_base_virt;
- bus->io_space.end = pci_io_base_virt + HADES_VIRT_IO_SIZE - 1;
- bus->io_space.name = pci_io_name;
-#if 1
- if (unlikely(request_resource(&ioport_resource, &bus->io_space) != 0))
- goto release_bus_mem_space;
-#endif
- /*
- * Set hardware dependent functions.
- */
-
- bus->m68k_pci_ops = &hades_pci_ops;
- bus->fixup = hades_fixup;
- bus->conf_device = hades_conf_device;
-
- /*
- * Select high to low edge for PCI interrupts.
- */
-
- tt_mfp.active_edge &= ~0x27;
-
- return bus;
-
-release_bus_mem_space:
- release_resource(&bus->mem_space);
-release_io_space:
- release_resource(&io_space);
-release_config_space:
- release_resource(&config_space);
-free_bus:
- kfree(bus);
-iounmap_base_virt:
- iounmap((void *)pci_io_base_virt);
-
- for (i = 0; i < N_SLOTS; i++)
- iounmap((void *)pci_conf_base_virt[i]);
-
- return NULL;
-}
-#endif
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index e0d3c8bfb40..1edde27fa32 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -20,6 +20,9 @@
#include <asm/atariints.h>
+DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
+
void __init
atari_sched_init(irq_handler_t timer_routine)
{
@@ -191,13 +194,14 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
}
if (!(ctrl & RTC_DM_BINARY)) {
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hour);
- BIN_TO_BCD(day);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(year);
- if (wday >= 0) BIN_TO_BCD(wday);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hour = bin2bcd(hour);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ year = bin2bcd(year);
+ if (wday >= 0)
+ wday = bin2bcd(wday);
}
}
@@ -252,13 +256,13 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
}
if (!(ctrl & RTC_DM_BINARY)) {
- BCD_TO_BIN(sec);
- BCD_TO_BIN(min);
- BCD_TO_BIN(hour);
- BCD_TO_BIN(day);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(year);
- BCD_TO_BIN(wday);
+ sec = bcd2bin(sec);
+ min = bcd2bin(min);
+ hour = bcd2bin(hour);
+ day = bcd2bin(day);
+ mon = bcd2bin(mon);
+ year = bcd2bin(year);
+ wday = bcd2bin(wday);
}
if (!(ctrl & RTC_24H)) {
@@ -318,7 +322,7 @@ int atari_tt_set_clock_mmss (unsigned long nowtime)
rtc_minutes = RTC_READ (RTC_MINUTES);
if (!(save_control & RTC_DM_BINARY))
- BCD_TO_BIN (rtc_minutes);
+ rtc_minutes = bcd2bin(rtc_minutes);
/* Since we're only adjusting minutes and seconds, don't interfere
with hour overflow. This avoids messing with unknown time zones
@@ -329,8 +333,8 @@ int atari_tt_set_clock_mmss (unsigned long nowtime)
{
if (!(save_control & RTC_DM_BINARY))
{
- BIN_TO_BCD (real_seconds);
- BIN_TO_BCD (real_minutes);
+ real_seconds = bin2bcd(real_seconds);
+ real_minutes = bin2bcd(real_minutes);
}
RTC_WRITE (RTC_SECONDS, real_seconds);
RTC_WRITE (RTC_MINUTES, real_minutes);
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index 9433a88a33c..65c9204ab9a 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -25,6 +25,7 @@
#include <linux/genhd.h>
#include <linux/rtc.h>
#include <linux/interrupt.h>
+#include <linux/bcd.h>
#include <asm/bootinfo.h>
#include <asm/system.h>
@@ -46,9 +47,6 @@ extern void bvme6000_reset (void);
extern void bvme6000_waitbut(void);
void bvme6000_set_vectors (void);
-static unsigned char bcd2bin (unsigned char b);
-static unsigned char bin2bcd (unsigned char b);
-
/* Save tick handler routine pointer, will point to do_timer() in
* kernel/sched.c, called via bvme6000_process_int() */
@@ -264,17 +262,6 @@ unsigned long bvme6000_gettimeoffset (void)
return v;
}
-static unsigned char bcd2bin (unsigned char b)
-{
- return ((b>>4)*10 + (b&15));
-}
-
-static unsigned char bin2bcd (unsigned char b)
-{
- return (((b/10)*16) + (b%10));
-}
-
-
/*
* Looks like op is non-zero for setting the clock, and zero for
* reading the clock.
diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c
index e8ac3f7d72d..808c9018b11 100644
--- a/arch/m68k/bvme6000/rtc.c
+++ b/arch/m68k/bvme6000/rtc.c
@@ -57,16 +57,16 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
rtc->msr = 0x40;
memset(&wtime, 0, sizeof(struct rtc_time));
do {
- wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
- wtime.tm_min = BCD2BIN(rtc->bcd_min);
- wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
- wtime.tm_mday = BCD2BIN(rtc->bcd_dom);
- wtime.tm_mon = BCD2BIN(rtc->bcd_mth)-1;
- wtime.tm_year = BCD2BIN(rtc->bcd_year);
+ wtime.tm_sec = bcd2bin(rtc->bcd_sec);
+ wtime.tm_min = bcd2bin(rtc->bcd_min);
+ wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+ wtime.tm_mday = bcd2bin(rtc->bcd_dom);
+ wtime.tm_mon = bcd2bin(rtc->bcd_mth)-1;
+ wtime.tm_year = bcd2bin(rtc->bcd_year);
if (wtime.tm_year < 70)
wtime.tm_year += 100;
- wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
- } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
+ wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
+ } while (wtime.tm_sec != bcd2bin(rtc->bcd_sec));
rtc->msr = msr;
local_irq_restore(flags);
return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -114,14 +114,14 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
rtc->t0cr_rtmr = yrs%4;
rtc->bcd_tenms = 0;
- rtc->bcd_sec = BIN2BCD(sec);
- rtc->bcd_min = BIN2BCD(min);
- rtc->bcd_hr = BIN2BCD(hrs);
- rtc->bcd_dom = BIN2BCD(day);
- rtc->bcd_mth = BIN2BCD(mon);
- rtc->bcd_year = BIN2BCD(yrs%100);
+ rtc->bcd_sec = bin2bcd(sec);
+ rtc->bcd_min = bin2bcd(min);
+ rtc->bcd_hr = bin2bcd(hrs);
+ rtc->bcd_dom = bin2bcd(day);
+ rtc->bcd_mth = bin2bcd(mon);
+ rtc->bcd_year = bin2bcd(yrs%100);
if (rtc_tm.tm_wday >= 0)
- rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
+ rtc->bcd_dow = bin2bcd(rtc_tm.tm_wday+1);
rtc->t0cr_rtmr = yrs%4 | 0x08;
rtc->msr = msr;
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index 3a7f6222550..55d5d6b680a 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -14,5 +14,4 @@ obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o module.o \
devres-y = ../../../kernel/irq/devres.o
-obj-$(CONFIG_PCI) += bios32.o
obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
diff --git a/arch/m68k/kernel/bios32.c b/arch/m68k/kernel/bios32.c
deleted file mode 100644
index af170c2be73..00000000000
--- a/arch/m68k/kernel/bios32.c
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * bios32.c - PCI BIOS functions for m68k systems.
- *
- * Written by Wout Klaren.
- *
- * Based on the DEC Alpha bios32.c by Dave Rusling and David Mosberger.
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#if 0
-# define DBG_DEVS(args) printk args
-#else
-# define DBG_DEVS(args)
-#endif
-
-#ifdef CONFIG_PCI
-
-/*
- * PCI support for Linux/m68k. Currently only the Hades is supported.
- *
- * The support for PCI bridges in the DEC Alpha version has
- * been removed in this version.
- */
-
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#include <asm/io.h>
-#include <asm/pci.h>
-#include <asm/uaccess.h>
-
-#define KB 1024
-#define MB (1024*KB)
-#define GB (1024*MB)
-
-#define MAJOR_REV 0
-#define MINOR_REV 5
-
-/*
- * Align VAL to ALIGN, which must be a power of two.
- */
-
-#define ALIGN(val,align) (((val) + ((align) - 1)) & ~((align) - 1))
-
-/*
- * Offsets relative to the I/O and memory base addresses from where resources
- * are allocated.
- */
-
-#define IO_ALLOC_OFFSET 0x00004000
-#define MEM_ALLOC_OFFSET 0x04000000
-
-/*
- * Declarations of hardware specific initialisation functions.
- */
-
-extern struct pci_bus_info *init_hades_pci(void);
-
-/*
- * Bus info structure of the PCI bus. A pointer to this structure is
- * put in the sysdata member of the pci_bus structure.
- */
-
-static struct pci_bus_info *bus_info;
-
-static int pci_modify = 1; /* If set, layout the PCI bus ourself. */
-static int skip_vga; /* If set do not modify base addresses
- of vga cards.*/
-static int disable_pci_burst; /* If set do not allow PCI bursts. */
-
-static unsigned int io_base;
-static unsigned int mem_base;
-
-/*
- * static void disable_dev(struct pci_dev *dev)
- *
- * Disable PCI device DEV so that it does not respond to I/O or memory
- * accesses.
- *
- * Parameters:
- *
- * dev - device to disable.
- */
-
-static void __init disable_dev(struct pci_dev *dev)
-{
- unsigned short cmd;
-
- if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
- (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
- (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
- return;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- cmd &= (~PCI_COMMAND_IO & ~PCI_COMMAND_MEMORY & ~PCI_COMMAND_MASTER);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
-}
-
-/*
- * static void layout_dev(struct pci_dev *dev)
- *
- * Layout memory and I/O for a device.
- *
- * Parameters:
- *
- * device - device to layout memory and I/O for.
- */
-
-static void __init layout_dev(struct pci_dev *dev)
-{
- unsigned short cmd;
- unsigned int base, mask, size, reg;
- unsigned int alignto;
- int i;
-
- /*
- * Skip video cards if requested.
- */
-
- if (((dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA) ||
- (dev->class >> 8 == PCI_CLASS_DISPLAY_VGA) ||
- (dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)) && skip_vga)
- return;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
-
- for (reg = PCI_BASE_ADDRESS_0, i = 0; reg <= PCI_BASE_ADDRESS_5; reg += 4, i++)
- {
- /*
- * Figure out how much space and of what type this
- * device wants.
- */
-
- pci_write_config_dword(dev, reg, 0xffffffff);
- pci_read_config_dword(dev, reg, &base);
-
- if (!base)
- {
- /* this base-address register is unused */
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- dev->resource[i].flags = 0;
- continue;
- }
-
- /*
- * We've read the base address register back after
- * writing all ones and so now we must decode it.
- */
-
- if (base & PCI_BASE_ADDRESS_SPACE_IO)
- {
- /*
- * I/O space base address register.
- */
-
- cmd |= PCI_COMMAND_IO;
-
- base &= PCI_BASE_ADDRESS_IO_MASK;
- mask = (~base << 1) | 0x1;
- size = (mask & base) & 0xffffffff;
-
- /*
- * Align to multiple of size of minimum base.
- */
-
- alignto = max_t(unsigned int, 0x040, size);
- base = ALIGN(io_base, alignto);
- io_base = base + size;
- pci_write_config_dword(dev, reg, base | PCI_BASE_ADDRESS_SPACE_IO);
-
- dev->resource[i].start = base;
- dev->resource[i].end = dev->resource[i].start + size - 1;
- dev->resource[i].flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
-
- DBG_DEVS(("layout_dev: IO address: %lX\n", base));
- }
- else
- {
- unsigned int type;
-
- /*
- * Memory space base address register.
- */
-
- cmd |= PCI_COMMAND_MEMORY;
- type = base & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
- base &= PCI_BASE_ADDRESS_MEM_MASK;
- mask = (~base << 1) | 0x1;
- size = (mask & base) & 0xffffffff;
- switch (type)
- {
- case PCI_BASE_ADDRESS_MEM_TYPE_32:
- case PCI_BASE_ADDRESS_MEM_TYPE_64:
- break;
-
- case PCI_BASE_ADDRESS_MEM_TYPE_1M:
- printk("bios32 WARNING: slot %d, function %d "
- "requests memory below 1MB---don't "
- "know how to do that.\n",
- PCI_SLOT(dev->devfn),
- PCI_FUNC(dev->devfn));
- continue;
- }
-
- /*
- * Align to multiple of size of minimum base.
- */
-
- alignto = max_t(unsigned int, 0x1000, size);
- base = ALIGN(mem_base, alignto);
- mem_base = base + size;
- pci_write_config_dword(dev, reg, base);
-
- dev->resource[i].start = base;
- dev->resource[i].end = dev->resource[i].start + size - 1;
- dev->resource[i].flags = IORESOURCE_MEM;
-
- if (type == PCI_BASE_ADDRESS_MEM_TYPE_64)
- {
- /*
- * 64-bit address, set the highest 32 bits
- * to zero.
- */
-
- reg += 4;
- pci_write_config_dword(dev, reg, 0);
-
- i++;
- dev->resource[i].start = 0;
- dev->resource[i].end = 0;
- dev->resource[i].flags = 0;
- }
- }
- }
-
- /*
- * Enable device:
- */
-
- if (dev->class >> 8 == PCI_CLASS_NOT_DEFINED ||
- dev->class >> 8 == PCI_CLASS_NOT_DEFINED_VGA ||
- dev->class >> 8 == PCI_CLASS_DISPLAY_VGA ||
- dev->class >> 8 == PCI_CLASS_DISPLAY_XGA)
- {
- /*
- * All of these (may) have I/O scattered all around
- * and may not use i/o-base address registers at all.
- * So we just have to always enable I/O to these
- * devices.
- */
- cmd |= PCI_COMMAND_IO;
- }
-
- pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MASTER);
-
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, (disable_pci_burst) ? 0 : 32);
-
- if (bus_info != NULL)
- bus_info->conf_device(dev); /* Machine dependent configuration. */
-
- DBG_DEVS(("layout_dev: bus %d slot 0x%x VID 0x%x DID 0x%x class 0x%x\n",
- dev->bus->number, PCI_SLOT(dev->devfn), dev->vendor, dev->device, dev->class));
-}
-
-/*
- * static void layout_bus(struct pci_bus *bus)
- *
- * Layout memory and I/O for all devices on the given bus.
- *
- * Parameters:
- *
- * bus - bus.
- */
-
-static void __init layout_bus(struct pci_bus *bus)
-{
- unsigned int bio, bmem;
- struct pci_dev *dev;
-
- DBG_DEVS(("layout_bus: starting bus %d\n", bus->number));
-
- if (!bus->devices && !bus->children)
- return;
-
- /*
- * Align the current bases on appropriate boundaries (4K for
- * IO and 1MB for memory).
- */
-
- bio = io_base = ALIGN(io_base, 4*KB);
- bmem = mem_base = ALIGN(mem_base, 1*MB);
-
- /*
- * PCI devices might have been setup by a PCI BIOS emulation
- * running under TOS. In these cases there is a
- * window during which two devices may have an overlapping
- * address range. To avoid this causing trouble, we first
- * turn off the I/O and memory address decoders for all PCI
- * devices. They'll be re-enabled only once all address
- * decoders are programmed consistently.
- */
-
- DBG_DEVS(("layout_bus: disable_dev for bus %d\n", bus->number));
-
- for (dev = bus->devices; dev; dev = dev->sibling)
- {
- if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
- (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
- disable_dev(dev);
- }
-
- /*
- * Allocate space to each device:
- */
-
- DBG_DEVS(("layout_bus: starting bus %d devices\n", bus->number));
-
- for (dev = bus->devices; dev; dev = dev->sibling)
- {
- if ((dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) ||
- (dev->class >> 8 == PCI_CLASS_BRIDGE_PCMCIA))
- layout_dev(dev);
- }
-
- DBG_DEVS(("layout_bus: bus %d finished\n", bus->number));
-}
-
-/*
- * static void pcibios_fixup(void)
- *
- * Layout memory and I/O of all devices on the PCI bus if 'pci_modify' is
- * true. This might be necessary because not every m68k machine with a PCI
- * bus has a PCI BIOS. This function should be called right after
- * pci_scan_bus() in pcibios_init().
- */
-
-static void __init pcibios_fixup(void)
-{
- if (pci_modify)
- {
- /*
- * Set base addresses for allocation of I/O and memory space.
- */
-
- io_base = bus_info->io_space.start + IO_ALLOC_OFFSET;
- mem_base = bus_info->mem_space.start + MEM_ALLOC_OFFSET;
-
- /*
- * Scan the tree, allocating PCI memory and I/O space.
- */
-
- layout_bus(pci_bus_b(pci_root.next));
- }
-
- /*
- * Fix interrupt assignments, etc.
- */
-
- bus_info->fixup(pci_modify);
-}
-
-/*
- * static void pcibios_claim_resources(struct pci_bus *bus)
- *
- * Claim all resources that are assigned to devices on the given bus.
- *
- * Parameters:
- *
- * bus - bus.
- */
-
-static void __init pcibios_claim_resources(struct pci_bus *bus)
-{
- struct pci_dev *dev;
- int i;
-
- while (bus)
- {
- for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
- {
- for (i = 0; i < PCI_NUM_RESOURCES; i++)
- {
- struct resource *r = &dev->resource[i];
- struct resource *pr;
- struct pci_bus_info *bus_info = (struct pci_bus_info *) dev->sysdata;
-
- if ((r->start == 0) || (r->parent != NULL))
- continue;
-#if 1
- if (r->flags & IORESOURCE_IO)
- pr = &bus_info->io_space;
- else
- pr = &bus_info->mem_space;
-#else
- if (r->flags & IORESOURCE_IO)
- pr = &ioport_resource;
- else
- pr = &iomem_resource;
-#endif
- if (request_resource(pr, r) < 0)
- {
- printk(KERN_ERR "PCI: Address space collision on region %d of device %s\n", i, dev->name);
- }
- }
- }
-
- if (bus->children)
- pcibios_claim_resources(bus->children);
-
- bus = bus->next;
- }
-}
-
-/*
- * int pcibios_assign_resource(struct pci_dev *dev, int i)
- *
- * Assign a new address to a PCI resource.
- *
- * Parameters:
- *
- * dev - device.
- * i - resource.
- *
- * Result: 0 if successful.
- */
-
-int __init pcibios_assign_resource(struct pci_dev *dev, int i)
-{
- struct resource *r = &dev->resource[i];
- struct resource *pr = pci_find_parent_resource(dev, r);
- unsigned long size = r->end + 1;
-
- if (!pr)
- return -EINVAL;
-
- if (r->flags & IORESOURCE_IO)
- {
- if (size > 0x100)
- return -EFBIG;
-
- if (allocate_resource(pr, r, size, bus_info->io_space.start +
- IO_ALLOC_OFFSET, bus_info->io_space.end, 1024))
- return -EBUSY;
- }
- else
- {
- if (allocate_resource(pr, r, size, bus_info->mem_space.start +
- MEM_ALLOC_OFFSET, bus_info->mem_space.end, size))
- return -EBUSY;
- }
-
- if (i < 6)
- pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + 4 * i, r->start);
-
- return 0;
-}
-
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
- struct pci_dev *dev;
- void *sysdata;
-
- sysdata = (bus->parent) ? bus->parent->sysdata : bus->sysdata;
-
- for (dev = bus->devices; (dev != NULL); dev = dev->sibling)
- dev->sysdata = sysdata;
-}
-
-void __init pcibios_init(void)
-{
- printk("Linux/m68k PCI BIOS32 revision %x.%02x\n", MAJOR_REV, MINOR_REV);
-
- bus_info = NULL;
-#ifdef CONFIG_HADES
- if (MACH_IS_HADES)
- bus_info = init_hades_pci();
-#endif
- if (bus_info != NULL)
- {
- printk("PCI: Probing PCI hardware\n");
- pci_scan_bus(0, bus_info->m68k_pci_ops, bus_info);
- pcibios_fixup();
- pcibios_claim_resources(pci_root);
- }
- else
- printk("PCI: No PCI bus detected\n");
-}
-
-char * __init pcibios_setup(char *str)
-{
- if (!strcmp(str, "nomodify"))
- {
- pci_modify = 0;
- return NULL;
- }
- else if (!strcmp(str, "skipvga"))
- {
- skip_vga = 1;
- return NULL;
- }
- else if (!strcmp(str, "noburst"))
- {
- disable_pci_burst = 1;
- return NULL;
- }
-
- return str;
-}
-#endif /* CONFIG_PCI */
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
index 6f8c080dd9f..2bb4245404d 100644
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -66,8 +66,8 @@ void dma_free_coherent(struct device *dev, size_t size,
}
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)
+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:
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index ded7dd2f67b..7e8a0d394e6 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -429,8 +429,9 @@ int show_interrupts(struct seq_file *p, void *v)
return 0;
}
+#ifdef CONFIG_PROC_FS
void init_irq_proc(void)
{
/* Insert /proc/irq driver here */
}
-
+#endif
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 7888cdf91f5..3042c2bc8c5 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -78,7 +78,7 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
static void default_idle(void)
{
if (!need_resched())
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
/* block out HSYNC on the atari (falcon) */
__asm__("stop #0x2200" : : : "cc");
#else
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 75b8340b254..6d813de2baf 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -883,8 +883,7 @@ void show_trace(unsigned long *stack)
if (i % 5 == 0)
printk("\n ");
#endif
- printk(" [<%08lx>]", addr);
- print_symbol(" %s\n", addr);
+ printk(" [<%08lx>] %pS\n", addr, (void *)addr);
i++;
}
}
@@ -900,10 +899,8 @@ void show_registers(struct pt_regs *regs)
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("PC: [<%08lx>] %pS\n", regs->pc, (void *)regs->pc);
+ printk("SR: %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",
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index 99b0784c055..f846d4e3e5e 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -34,10 +34,10 @@ SECTIONS
CONSTRUCTORS
}
- .bss : { *(.bss) } /* BSS */
-
. = ALIGN(16);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) } :data
+ .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
+ .bss : { *(.bss) } /* BSS */
_edata = .; /* End of data section */
@@ -48,7 +48,7 @@ SECTIONS
_sinittext = .;
INIT_TEXT
_einittext = .;
- }
+ } :data
.init.data : { INIT_DATA }
. = ALIGN(16);
__setup_start = .;
@@ -74,6 +74,7 @@ SECTIONS
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
#endif
+ NOTES
. = ALIGN(8192);
__init_end = .;
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index 46b7d6035aa..df620ac2a29 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -66,8 +66,10 @@ static struct vm_struct *get_io_area(unsigned long size)
for (p = &iolist; (tmp = *p) ; p = &tmp->next) {
if (size + addr < (unsigned long)tmp->addr)
break;
- if (addr > KMAP_END-size)
+ if (addr > KMAP_END-size) {
+ kfree(area);
return NULL;
+ }
addr = tmp->size + (unsigned long)tmp->addr;
}
area->addr = (void *)addr;
diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c
index 432a9f13b2e..cea5e3e4e63 100644
--- a/arch/m68k/mvme16x/rtc.c
+++ b/arch/m68k/mvme16x/rtc.c
@@ -52,15 +52,15 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
/* Ensure clock and real-time-mode-register are accessible */
rtc->ctrl = RTC_READ;
memset(&wtime, 0, sizeof(struct rtc_time));
- wtime.tm_sec = BCD2BIN(rtc->bcd_sec);
- wtime.tm_min = BCD2BIN(rtc->bcd_min);
- wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
- wtime.tm_mday = BCD2BIN(rtc->bcd_dom);
- wtime.tm_mon = BCD2BIN(rtc->bcd_mth)-1;
- wtime.tm_year = BCD2BIN(rtc->bcd_year);
+ wtime.tm_sec = bcd2bin(rtc->bcd_sec);
+ wtime.tm_min = bcd2bin(rtc->bcd_min);
+ wtime.tm_hour = bcd2bin(rtc->bcd_hr);
+ wtime.tm_mday = bcd2bin(rtc->bcd_dom);
+ wtime.tm_mon = bcd2bin(rtc->bcd_mth)-1;
+ wtime.tm_year = bcd2bin(rtc->bcd_year);
if (wtime.tm_year < 70)
wtime.tm_year += 100;
- wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
+ wtime.tm_wday = bcd2bin(rtc->bcd_dow)-1;
rtc->ctrl = 0;
local_irq_restore(flags);
return copy_to_user(argp, &wtime, sizeof wtime) ?
@@ -104,12 +104,12 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
local_irq_save(flags);
rtc->ctrl = RTC_WRITE;
- rtc->bcd_sec = BIN2BCD(sec);
- rtc->bcd_min = BIN2BCD(min);
- rtc->bcd_hr = BIN2BCD(hrs);
- rtc->bcd_dom = BIN2BCD(day);
- rtc->bcd_mth = BIN2BCD(mon);
- rtc->bcd_year = BIN2BCD(yrs%100);
+ rtc->bcd_sec = bin2bcd(sec);
+ rtc->bcd_min = bin2bcd(min);
+ rtc->bcd_hr = bin2bcd(hrs);
+ rtc->bcd_dom = bin2bcd(day);
+ rtc->bcd_mth = bin2bcd(mon);
+ rtc->bcd_year = bin2bcd(yrs%100);
rtc->ctrl = 0;
local_irq_restore(flags);
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index be9de2f3dc4..9c7eefa3f98 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -23,6 +23,7 @@
#include <linux/serial_reg.h>
#include <linux/rtc.h>
#include <linux/vt_kern.h>
+#include <linux/bcd.h>
#include <asm/io.h>
#include <asm/rtc.h>
@@ -216,17 +217,6 @@ int q40_parse_bootinfo(const struct bi_record *rec)
}
-static inline unsigned char bcd2bin(unsigned char b)
-{
- return (b >> 4) * 10 + (b & 15);
-}
-
-static inline unsigned char bin2bcd(unsigned char b)
-{
- return (b / 10) * 16 + (b % 10);
-}
-
-
static unsigned long q40_gettimeoffset(void)
{
return 5000 * (ql_ticks != 0);
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index f5eaafb00d2..536a04aaf22 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -47,23 +47,23 @@ int sun3x_hwclk(int set, struct rtc_time *t)
if(set) {
h->csr |= C_WRITE;
- h->sec = BIN2BCD(t->tm_sec);
- h->min = BIN2BCD(t->tm_min);
- h->hour = BIN2BCD(t->tm_hour);
- h->wday = BIN2BCD(t->tm_wday);
- h->mday = BIN2BCD(t->tm_mday);
- h->month = BIN2BCD(t->tm_mon);
- h->year = BIN2BCD(t->tm_year);
+ h->sec = bin2bcd(t->tm_sec);
+ h->min = bin2bcd(t->tm_min);
+ h->hour = bin2bcd(t->tm_hour);
+ h->wday = bin2bcd(t->tm_wday);
+ h->mday = bin2bcd(t->tm_mday);
+ h->month = bin2bcd(t->tm_mon);
+ h->year = bin2bcd(t->tm_year);
h->csr &= ~C_WRITE;
} else {
h->csr |= C_READ;
- t->tm_sec = BCD2BIN(h->sec);
- t->tm_min = BCD2BIN(h->min);
- t->tm_hour = BCD2BIN(h->hour);
- t->tm_wday = BCD2BIN(h->wday);
- t->tm_mday = BCD2BIN(h->mday);
- t->tm_mon = BCD2BIN(h->month);
- t->tm_year = BCD2BIN(h->year);
+ t->tm_sec = bcd2bin(h->sec);
+ t->tm_min = bcd2bin(h->min);
+ t->tm_hour = bcd2bin(h->hour);
+ t->tm_wday = bcd2bin(h->wday);
+ t->tm_mday = bcd2bin(h->mday);
+ t->tm_mon = bcd2bin(h->month);
+ t->tm_year = bcd2bin(h->year);
h->csr &= ~C_READ;
}
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index cd5fbf6f078..b905744d791 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -52,6 +52,7 @@ config BCM47XX
select SSB
select SSB_DRIVER_MIPS
select SSB_DRIVER_EXTIF
+ select SSB_EMBEDDED
select SSB_PCICORE_HOSTMODE if PCI
select GENERIC_GPIO
select SYS_HAS_EARLY_PRINTK
diff --git a/arch/mips/bcm47xx/gpio.c b/arch/mips/bcm47xx/gpio.c
index f5a53acf995..9b798800258 100644
--- a/arch/mips/bcm47xx/gpio.c
+++ b/arch/mips/bcm47xx/gpio.c
@@ -12,68 +12,51 @@
#include <asm/mach-bcm47xx/bcm47xx.h>
#include <asm/mach-bcm47xx/gpio.h>
-int bcm47xx_gpio_to_irq(unsigned gpio)
+#if (BCM47XX_CHIPCO_GPIO_LINES > BCM47XX_EXTIF_GPIO_LINES)
+static DECLARE_BITMAP(gpio_in_use, BCM47XX_CHIPCO_GPIO_LINES);
+#else
+static DECLARE_BITMAP(gpio_in_use, BCM47XX_EXTIF_GPIO_LINES);
+#endif
+
+int gpio_request(unsigned gpio, const char *tag)
{
- if (ssb_bcm47xx.chipco.dev)
- return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
- else if (ssb_bcm47xx.extif.dev)
- return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
- else
+ if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
return -EINVAL;
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_to_irq);
-int bcm47xx_gpio_get_value(unsigned gpio)
-{
- if (ssb_bcm47xx.chipco.dev)
- return ssb_chipco_gpio_in(&ssb_bcm47xx.chipco, 1 << gpio);
- else if (ssb_bcm47xx.extif.dev)
- return ssb_extif_gpio_in(&ssb_bcm47xx.extif, 1 << gpio);
- else
- return 0;
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_get_value);
+ if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return -EINVAL;
-void bcm47xx_gpio_set_value(unsigned gpio, int value)
-{
- if (ssb_bcm47xx.chipco.dev)
- ssb_chipco_gpio_out(&ssb_bcm47xx.chipco,
- 1 << gpio,
- value ? 1 << gpio : 0);
- else if (ssb_bcm47xx.extif.dev)
- ssb_extif_gpio_out(&ssb_bcm47xx.extif,
- 1 << gpio,
- value ? 1 << gpio : 0);
-}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_set_value);
+ if (test_and_set_bit(gpio, gpio_in_use))
+ return -EBUSY;
-int bcm47xx_gpio_direction_input(unsigned gpio)
-{
- if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES))
- ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco,
- 1 << gpio, 0);
- else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES))
- ssb_extif_gpio_outen(&ssb_bcm47xx.extif,
- 1 << gpio, 0);
- else
- return -EINVAL;
return 0;
}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_input);
+EXPORT_SYMBOL(gpio_request);
-int bcm47xx_gpio_direction_output(unsigned gpio, int value)
+void gpio_free(unsigned gpio)
{
- bcm47xx_gpio_set_value(gpio, value);
+ if (ssb_chipco_available(&ssb_bcm47xx.chipco) &&
+ ((unsigned)gpio >= BCM47XX_CHIPCO_GPIO_LINES))
+ return;
+
+ if (ssb_extif_available(&ssb_bcm47xx.extif) &&
+ ((unsigned)gpio >= BCM47XX_EXTIF_GPIO_LINES))
+ return;
+
+ clear_bit(gpio, gpio_in_use);
+}
+EXPORT_SYMBOL(gpio_free);
- if (ssb_bcm47xx.chipco.dev && (gpio < BCM47XX_CHIPCO_GPIO_LINES))
- ssb_chipco_gpio_outen(&ssb_bcm47xx.chipco,
- 1 << gpio, 1 << gpio);
- else if (ssb_bcm47xx.extif.dev && (gpio < BCM47XX_EXTIF_GPIO_LINES))
- ssb_extif_gpio_outen(&ssb_bcm47xx.extif,
- 1 << gpio, 1 << gpio);
+int gpio_to_irq(unsigned gpio)
+{
+ if (ssb_chipco_available(&ssb_bcm47xx.chipco))
+ return ssb_mips_irq(ssb_bcm47xx.chipco.dev) + 2;
+ else if (ssb_extif_available(&ssb_bcm47xx.extif))
+ return ssb_mips_irq(ssb_bcm47xx.extif.dev) + 2;
else
return -EINVAL;
- return 0;
}
-EXPORT_SYMBOL_GPL(bcm47xx_gpio_direction_output);
+EXPORT_SYMBOL_GPL(gpio_to_irq);
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 8d36f186890..2f580fa160c 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -27,6 +27,7 @@
#include <linux/types.h>
#include <linux/ssb/ssb.h>
+#include <linux/ssb/ssb_embedded.h>
#include <asm/bootinfo.h>
#include <asm/reboot.h>
#include <asm/time.h>
@@ -41,7 +42,7 @@ static void bcm47xx_machine_restart(char *command)
printk(KERN_ALERT "Please stand by while rebooting the system...\n");
local_irq_disable();
/* Set the watchdog timer to reset immediately */
- ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 1);
+ ssb_watchdog_timer_set(&ssb_bcm47xx, 1);
while (1)
cpu_relax();
}
@@ -50,7 +51,7 @@ static void bcm47xx_machine_halt(void)
{
/* Disable interrupts and watchdog and spin forever */
local_irq_disable();
- ssb_chipco_watchdog_timer_set(&ssb_bcm47xx.chipco, 0);
+ ssb_watchdog_timer_set(&ssb_bcm47xx, 0);
while (1)
cpu_relax();
}
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
index d1d90c9ef2f..ef00e7f58c2 100644
--- a/arch/mips/bcm47xx/wgt634u.c
+++ b/arch/mips/bcm47xx/wgt634u.c
@@ -11,6 +11,9 @@
#include <linux/leds.h>
#include <linux/mtd/physmap.h>
#include <linux/ssb/ssb.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/gpio.h>
#include <asm/mach-bcm47xx/bcm47xx.h>
/* GPIO definitions for the WGT634U */
@@ -99,6 +102,30 @@ static struct platform_device *wgt634u_devices[] __initdata = {
&wgt634u_gpio_leds,
};
+static irqreturn_t gpio_interrupt(int irq, void *ignored)
+{
+ int state;
+
+ /* Interrupts are shared, check if the current one is
+ a GPIO interrupt. */
+ if (!ssb_chipco_irq_status(&ssb_bcm47xx.chipco,
+ SSB_CHIPCO_IRQ_GPIO))
+ return IRQ_NONE;
+
+ state = gpio_get_value(WGT634U_GPIO_RESET);
+
+ /* Interrupt are level triggered, revert the interrupt polarity
+ to clear the interrupt. */
+ gpio_polarity(WGT634U_GPIO_RESET, state);
+
+ if (!state) {
+ printk(KERN_INFO "Reset button pressed");
+ ctrl_alt_del();
+ }
+
+ return IRQ_HANDLED;
+}
+
static int __init wgt634u_init(void)
{
/* There is no easy way to detect that we are running on a WGT634U
@@ -112,6 +139,19 @@ static int __init wgt634u_init(void)
((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
(et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+
+ printk(KERN_INFO "WGT634U machine detected.\n");
+
+ if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
+ gpio_interrupt, IRQF_SHARED,
+ "WGT634U GPIO", &ssb_bcm47xx.chipco)) {
+ gpio_direction_input(WGT634U_GPIO_RESET);
+ gpio_intmask(WGT634U_GPIO_RESET, 1);
+ ssb_chipco_irq_mask(&ssb_bcm47xx.chipco,
+ SSB_CHIPCO_IRQ_GPIO,
+ SSB_CHIPCO_IRQ_GPIO);
+ }
+
wgt634u_flash_data.width = mcore->flash_buswidth;
wgt634u_flash_resource.start = mcore->flash_window;
wgt634u_flash_resource.end = mcore->flash_window
diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c
index d9560477366..91cbd959ab6 100644
--- a/arch/mips/emma2rh/common/irq.c
+++ b/arch/mips/emma2rh/common/irq.c
@@ -29,7 +29,6 @@
#include <asm/system.h>
#include <asm/mipsregs.h>
-#include <asm/debug.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
diff --git a/arch/mips/emma2rh/common/prom.c b/arch/mips/emma2rh/common/prom.c
index 5e92b3a9c5b..e14a2e3d884 100644
--- a/arch/mips/emma2rh/common/prom.c
+++ b/arch/mips/emma2rh/common/prom.c
@@ -30,7 +30,6 @@
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/emma2rh/emma2rh.h>
-#include <asm/debug.h>
const char *get_system_type(void)
{
diff --git a/arch/mips/emma2rh/markeins/platform.c b/arch/mips/emma2rh/markeins/platform.c
index d70627de7cf..fb9cda253ab 100644
--- a/arch/mips/emma2rh/markeins/platform.c
+++ b/arch/mips/emma2rh/markeins/platform.c
@@ -35,7 +35,6 @@
#include <asm/irq.h>
#include <asm/reboot.h>
#include <asm/traps.h>
-#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h>
diff --git a/include/asm-mips/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h
index fa4328f9124..fa4328f9124 100644
--- a/include/asm-mips/cevt-r4k.h
+++ b/arch/mips/include/asm/cevt-r4k.h
diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h
index cfc8f4d618c..d8ff4cd89ab 100644
--- a/arch/mips/include/asm/mach-bcm47xx/gpio.h
+++ b/arch/mips/include/asm/mach-bcm47xx/gpio.h
@@ -9,47 +9,46 @@
#ifndef __BCM47XX_GPIO_H
#define __BCM47XX_GPIO_H
+#include <linux/ssb/ssb_embedded.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+
#define BCM47XX_EXTIF_GPIO_LINES 5
#define BCM47XX_CHIPCO_GPIO_LINES 16
-extern int bcm47xx_gpio_to_irq(unsigned gpio);
-extern int bcm47xx_gpio_get_value(unsigned gpio);
-extern void bcm47xx_gpio_set_value(unsigned gpio, int value);
-extern int bcm47xx_gpio_direction_input(unsigned gpio);
-extern int bcm47xx_gpio_direction_output(unsigned gpio, int value);
-
-static inline int gpio_request(unsigned gpio, const char *label)
-{
- return 0;
-}
+extern int gpio_request(unsigned gpio, const char *label);
+extern void gpio_free(unsigned gpio);
+extern int gpio_to_irq(unsigned gpio);
-static inline void gpio_free(unsigned gpio)
+static inline int gpio_get_value(unsigned gpio)
{
+ return ssb_gpio_in(&ssb_bcm47xx, 1 << gpio);
}
-static inline int gpio_to_irq(unsigned gpio)
+static inline void gpio_set_value(unsigned gpio, int value)
{
- return bcm47xx_gpio_to_irq(gpio);
+ ssb_gpio_out(&ssb_bcm47xx, 1 << gpio, value ? 1 << gpio : 0);
}
-static inline int gpio_get_value(unsigned gpio)
+static inline int gpio_direction_input(unsigned gpio)
{
- return bcm47xx_gpio_get_value(gpio);
+ return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 0);
}
-static inline void gpio_set_value(unsigned gpio, int value)
+static inline int gpio_direction_output(unsigned gpio, int value)
{
- bcm47xx_gpio_set_value(gpio, value);
+ return ssb_gpio_outen(&ssb_bcm47xx, 1 << gpio, 1 << gpio);
}
-static inline int gpio_direction_input(unsigned gpio)
+static int gpio_intmask(unsigned gpio, int value)
{
- return bcm47xx_gpio_direction_input(gpio);
+ return ssb_gpio_intmask(&ssb_bcm47xx, 1 << gpio,
+ value ? 1 << gpio : 0);
}
-static inline int gpio_direction_output(unsigned gpio, int value)
+static int gpio_polarity(unsigned gpio, int value)
{
- return bcm47xx_gpio_direction_output(gpio, value);
+ return ssb_gpio_polarity(&ssb_bcm47xx, 1 << gpio,
+ value ? 1 << gpio : 0);
}
diff --git a/arch/mips/include/asm/mach-bcm47xx/war.h b/arch/mips/include/asm/mach-bcm47xx/war.h
index 4a2b7986b58..87cd4651dda 100644
--- a/arch/mips/include/asm/mach-bcm47xx/war.h
+++ b/arch/mips/include/asm/mach-bcm47xx/war.h
@@ -5,8 +5,8 @@
*
* Copyright (C) 2002, 2004, 2007 by Ralf Baechle <ralf@linux-mips.org>
*/
-#ifndef __ASM_MIPS_MACH_BCM947XX_WAR_H
-#define __ASM_MIPS_MACH_BCM947XX_WAR_H
+#ifndef __ASM_MIPS_MACH_BCM47XX_WAR_H
+#define __ASM_MIPS_MACH_BCM47XX_WAR_H
#define R4600_V1_INDEX_ICACHEOP_WAR 0
#define R4600_V1_HIT_CACHEOP_WAR 0
@@ -22,4 +22,4 @@
#define R10000_LLSC_WAR 0
#define MIPS34K_MISSED_ITLB_WAR 0
-#endif /* __ASM_MIPS_MACH_BCM947XX_WAR_H */
+#endif /* __ASM_MIPS_MACH_BCM47XX_WAR_H */
diff --git a/arch/mips/include/asm/mach-ip22/ds1286.h b/arch/mips/include/asm/mach-ip22/ds1286.h
deleted file mode 100644
index f19f1eafbc7..00000000000
--- a/arch/mips/include/asm/mach-ip22/ds1286.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 1998, 2001, 03 by Ralf Baechle
- *
- * RTC routines for PC style attached Dallas chip.
- */
-#ifndef __ASM_MACH_IP22_DS1286_H
-#define __ASM_MACH_IP22_DS1286_H
-
-#include <asm/sgi/hpc3.h>
-
-#define rtc_read(reg) (hpc3c0->rtcregs[(reg)] & 0xff)
-#define rtc_write(data, reg) do { hpc3c0->rtcregs[(reg)] = (data); } while(0)
-
-#endif /* __ASM_MACH_IP22_DS1286_H */
diff --git a/arch/mips/include/asm/mach-ip28/ds1286.h b/arch/mips/include/asm/mach-ip28/ds1286.h
deleted file mode 100644
index 471bb9a33e0..00000000000
--- a/arch/mips/include/asm/mach-ip28/ds1286.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __ASM_MACH_IP28_DS1286_H
-#define __ASM_MACH_IP28_DS1286_H
-#include <asm/mach-ip22/ds1286.h>
-#endif /* __ASM_MACH_IP28_DS1286_H */
diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h
index 5d98a3cb85b..1a1f320c30d 100644
--- a/arch/mips/include/asm/spinlock.h
+++ b/arch/mips/include/asm/spinlock.h
@@ -147,7 +147,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lock)
" ori %[ticket], %[ticket], 0x2000 \n"
" xori %[ticket], %[ticket], 0x2000 \n"
" sc %[ticket], %[ticket_ptr] \n"
- " beqzl %[ticket], 2f \n"
+ " beqzl %[ticket], 1b \n"
: [ticket_ptr] "+m" (lock->lock),
[ticket] "=&r" (tmp));
} else {
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 2fefb14414b..aa2c55e3b55 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -63,41 +63,6 @@
#define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL))
#endif
-/*
- * Revalidate the inode. This is required for proper NFS attribute caching.
- */
-
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
- struct compat_stat tmp;
-
- if (!new_valid_dev(stat->dev) || !new_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.st_dev = new_encode_dev(stat->dev);
- tmp.st_ino = stat->ino;
- if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
- return -EOVERFLOW;
- tmp.st_mode = stat->mode;
- tmp.st_nlink = stat->nlink;
- SET_UID(tmp.st_uid, stat->uid);
- SET_GID(tmp.st_gid, stat->gid);
- tmp.st_rdev = new_encode_dev(stat->rdev);
- tmp.st_size = stat->size;
- tmp.st_atime = stat->atime.tv_sec;
- tmp.st_mtime = stat->mtime.tv_sec;
- tmp.st_ctime = stat->ctime.tv_sec;
-#ifdef STAT_HAVE_NSEC
- tmp.st_atime_nsec = stat->atime.tv_nsec;
- tmp.st_mtime_nsec = stat->mtime.tv_nsec;
- tmp.st_ctime_nsec = stat->ctime.tv_nsec;
-#endif
- tmp.st_blocks = stat->blocks;
- tmp.st_blksize = stat->blksize;
- return copy_to_user(statbuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
-}
-
asmlinkage unsigned long
sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
unsigned long flags, unsigned long fd, unsigned long pgoff)
@@ -168,72 +133,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
return sys_ftruncate(fd, merge_64(a2, a3));
}
-static inline long
-get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
- return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
- (__get_user(o->tv_sec, &i->tv_sec) |
- __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long
-put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
- return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
- (__put_user(i->tv_sec, &o->tv_sec) |
- __put_user(i->tv_usec, &o->tv_usec)));
-}
-
-extern struct timezone sys_tz;
-
-asmlinkage int
-sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
- long usec;
-
- if (!access_ok(VERIFY_READ, i, sizeof(*i)))
- return -EFAULT;
- if (__get_user(o->tv_sec, &i->tv_sec))
- return -EFAULT;
- if (__get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-asmlinkage int
-sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_ts32(&kts, tv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
unsigned int offset_low, loff_t __user * result,
unsigned int origin)
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index 75bb1300dd7..26760cad8b6 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -39,7 +39,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "processor\t\t: %ld\n", n);
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : "");
- seq_printf(m, fmt, __cpu_name[smp_processor_id()],
+ seq_printf(m, fmt, __cpu_name[n],
(version >> 4) & 0x0f, version & 0x0f,
(fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 324c5499dec..e266b3aa656 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -214,7 +214,7 @@ EXPORT(sysn32_call_table)
PTR sys_fchown
PTR sys_lchown
PTR sys_umask
- PTR sys32_gettimeofday
+ PTR compat_sys_gettimeofday
PTR compat_sys_getrlimit /* 6095 */
PTR compat_sys_getrusage
PTR compat_sys_sysinfo
@@ -279,7 +279,7 @@ EXPORT(sysn32_call_table)
PTR sys_chroot
PTR sys_sync
PTR sys_acct
- PTR sys32_settimeofday
+ PTR compat_sys_settimeofday
PTR compat_sys_mount /* 6160 */
PTR sys_umount
PTR sys_swapon
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 85fedac99a5..6c7ef8313eb 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -283,8 +283,8 @@ sys_call_table:
PTR compat_sys_setrlimit /* 4075 */
PTR compat_sys_getrlimit
PTR compat_sys_getrusage
- PTR sys32_gettimeofday
- PTR sys32_settimeofday
+ PTR compat_sys_gettimeofday
+ PTR compat_sys_settimeofday
PTR sys_getgroups /* 4080 */
PTR sys_setgroups
PTR sys_ni_syscall /* old_select */
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index afb119f3568..58738c8d754 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -104,7 +104,7 @@ SECTIONS
. = ALIGN(_PAGE_SIZE);
__nosave_end = .;
- . = ALIGN(32);
+ . = ALIGN(1 << CONFIG_MIPS_L1_CACHE_SHIFT);
.data.cacheline_aligned : {
*(.data.cacheline_aligned)
}
diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c
index 866881ec0cf..8f88886feb1 100644
--- a/arch/mips/lasat/sysctl.c
+++ b/arch/mips/lasat/sysctl.c
@@ -38,14 +38,13 @@
#endif
/* Strategy function to write EEPROM after changing string entry */
-int sysctl_lasatstring(ctl_table *table, int *name, int nlen,
+int sysctl_lasatstring(ctl_table *table,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
int r;
- r = sysctl_string(table, name,
- nlen, oldval, oldlenp, newval, newlen);
+ r = sysctl_string(table, oldval, oldlenp, newval, newlen);
if (r < 0)
return r;
@@ -113,13 +112,13 @@ int proc_dolasatrtc(ctl_table *table, int write, struct file *filp,
#endif
/* Sysctl for setting the IP addresses */
-int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
+int sysctl_lasat_intvec(ctl_table *table,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
int r;
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+ r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
if (r < 0)
return r;
@@ -131,7 +130,7 @@ int sysctl_lasat_intvec(ctl_table *table, int *name, int nlen,
#ifdef CONFIG_DS1603
/* Same for RTC */
-int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
+int sysctl_lasat_rtc(ctl_table *table,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
@@ -140,7 +139,7 @@ int sysctl_lasat_rtc(ctl_table *table, int *name, int nlen,
rtctmp = read_persistent_clock();
if (rtctmp < 0)
rtctmp = 0;
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+ r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
if (r < 0)
return r;
if (newval && newlen)
@@ -211,13 +210,13 @@ int proc_lasat_ip(ctl_table *table, int write, struct file *filp,
}
#endif
-static int sysctl_lasat_prid(ctl_table *table, int *name, int nlen,
+static int sysctl_lasat_prid(ctl_table *table,
void *oldval, size_t *oldlenp,
void *newval, size_t newlen)
{
int r;
- r = sysctl_intvec(table, name, nlen, oldval, oldlenp, newval, newlen);
+ r = sysctl_intvec(table, oldval, oldlenp, newval, newlen);
if (r < 0)
return r;
if (newval && newlen) {
diff --git a/arch/mips/pci/fixup-emma2rh.c b/arch/mips/pci/fixup-emma2rh.c
index a2705895561..846eae9cdd0 100644
--- a/arch/mips/pci/fixup-emma2rh.c
+++ b/arch/mips/pci/fixup-emma2rh.c
@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <asm/bootinfo.h>
-#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h>
diff --git a/arch/mips/pci/ops-pnx8550.c b/arch/mips/pci/ops-pnx8550.c
index 0e160d9f07c..1e6213fa7bd 100644
--- a/arch/mips/pci/ops-pnx8550.c
+++ b/arch/mips/pci/ops-pnx8550.c
@@ -29,8 +29,6 @@
#include <asm/mach-pnx8550/pci.h>
#include <asm/mach-pnx8550/glb.h>
-#include <asm/debug.h>
-
static inline void clear_status(void)
{
diff --git a/arch/mips/pci/pci-emma2rh.c b/arch/mips/pci/pci-emma2rh.c
index d99591a0cdf..772e283daa6 100644
--- a/arch/mips/pci/pci-emma2rh.c
+++ b/arch/mips/pci/pci-emma2rh.c
@@ -29,7 +29,6 @@
#include <linux/pci.h>
#include <asm/bootinfo.h>
-#include <asm/debug.h>
#include <asm/emma2rh/emma2rh.h>
diff --git a/arch/mips/pci/pci.c b/arch/mips/pci/pci.c
index c7fe6ec621e..a377e9d2d02 100644
--- a/arch/mips/pci/pci.c
+++ b/arch/mips/pci/pci.c
@@ -34,6 +34,8 @@ static struct pci_controller *hose_head, **hose_tail = &hose_head;
unsigned long PCIBIOS_MIN_IO = 0x0000;
unsigned long PCIBIOS_MIN_MEM = 0;
+static int pci_initialized;
+
/*
* We need to avoid collisions with `mirrored' VGA ports
* and other strange ISA hardware, so we always want the
@@ -74,6 +76,42 @@ pcibios_align_resource(void *data, struct resource *res,
res->start = start;
}
+static void __devinit pcibios_scanbus(struct pci_controller *hose)
+{
+ static int next_busno;
+ static int need_domain_info;
+ struct pci_bus *bus;
+
+ if (!hose->iommu)
+ PCI_DMA_BUS_IS_PHYS = 1;
+
+ if (hose->get_busno && pci_probe_only)
+ next_busno = (*hose->get_busno)();
+
+ bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
+ hose->bus = bus;
+
+ need_domain_info = need_domain_info || hose->index;
+ hose->need_domain_info = need_domain_info;
+ if (bus) {
+ next_busno = bus->subordinate + 1;
+ /* Don't allow 8-bit bus number overflow inside the hose -
+ reserve some space for bridges. */
+ if (next_busno > 224) {
+ next_busno = 0;
+ need_domain_info = 1;
+ }
+
+ if (!pci_probe_only) {
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+ pci_enable_bridges(bus);
+ }
+ }
+}
+
+static DEFINE_MUTEX(pci_scan_mutex);
+
void __devinit register_pci_controller(struct pci_controller *hose)
{
if (request_resource(&iomem_resource, hose->mem_resource) < 0)
@@ -93,6 +131,17 @@ void __devinit register_pci_controller(struct pci_controller *hose)
printk(KERN_WARNING
"registering PCI controller with io_map_base unset\n");
}
+
+ /*
+ * Scan the bus if it is register after the PCI subsystem
+ * initialization.
+ */
+ if (pci_initialized) {
+ mutex_lock(&pci_scan_mutex);
+ pcibios_scanbus(hose);
+ mutex_unlock(&pci_scan_mutex);
+ }
+
return;
out:
@@ -125,38 +174,15 @@ static u8 __init common_swizzle(struct pci_dev *dev, u8 *pinp)
static int __init pcibios_init(void)
{
struct pci_controller *hose;
- struct pci_bus *bus;
- int next_busno;
- int need_domain_info = 0;
/* Scan all of the recorded PCI controllers. */
- for (next_busno = 0, hose = hose_head; hose; hose = hose->next) {
-
- if (!hose->iommu)
- PCI_DMA_BUS_IS_PHYS = 1;
-
- if (hose->get_busno && pci_probe_only)
- next_busno = (*hose->get_busno)();
-
- bus = pci_scan_bus(next_busno, hose->pci_ops, hose);
- hose->bus = bus;
- need_domain_info = need_domain_info || hose->index;
- hose->need_domain_info = need_domain_info;
- if (bus) {
- next_busno = bus->subordinate + 1;
- /* Don't allow 8-bit bus number overflow inside the hose -
- reserve some space for bridges. */
- if (next_busno > 224) {
- next_busno = 0;
- need_domain_info = 1;
- }
- }
- }
+ for (hose = hose_head; hose; hose = hose->next)
+ pcibios_scanbus(hose);
- if (!pci_probe_only)
- pci_assign_unassigned_resources();
pci_fixup_irqs(common_swizzle, pcibios_map_irq);
+ pci_initialized = 1;
+
return 0;
}
diff --git a/arch/mips/rb532/time.c b/arch/mips/rb532/time.c
index 8e7a46855b5..1377d599f0e 100644
--- a/arch/mips/rb532/time.c
+++ b/arch/mips/rb532/time.c
@@ -28,7 +28,6 @@
#include <linux/timex.h>
#include <asm/mipsregs.h>
-#include <asm/debug.h>
#include <asm/time.h>
#include <asm/mach-rc32434/rc32434.h>
diff --git a/arch/mips/sgi-ip22/ip22-platform.c b/arch/mips/sgi-ip22/ip22-platform.c
index 52486c4d2b0..deddbf0ebe5 100644
--- a/arch/mips/sgi-ip22/ip22-platform.c
+++ b/arch/mips/sgi-ip22/ip22-platform.c
@@ -192,3 +192,18 @@ static int __init sgi_button_devinit(void)
}
device_initcall(sgi_button_devinit);
+
+static int __init sgi_ds1286_devinit(void)
+{
+ struct resource res;
+
+ memset(&res, 0, sizeof(res));
+ res.start = HPC3_CHIP0_BASE + offsetof(struct hpc3_regs, rtcregs);
+ res.end = res.start + sizeof(hpc3c0->rtcregs) - 1;
+ res.flags = IORESOURCE_MEM;
+
+ return IS_ERR(platform_device_register_simple("rtc-ds1286", -1,
+ &res, 1));
+}
+
+device_initcall(sgi_ds1286_devinit);
diff --git a/arch/mips/sgi-ip22/ip22-setup.c b/arch/mips/sgi-ip22/ip22-setup.c
index 896a1ef8482..b9a931358e2 100644
--- a/arch/mips/sgi-ip22/ip22-setup.c
+++ b/arch/mips/sgi-ip22/ip22-setup.c
@@ -4,7 +4,6 @@
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
* Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
*/
-#include <linux/ds1286.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kdev_t.h>
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 10e50549165..3dcb27ec0c5 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -10,7 +10,6 @@
* Copyright (C) 2003, 06 Ralf Baechle (ralf@linux-mips.org)
*/
#include <linux/bcd.h>
-#include <linux/ds1286.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kernel.h>
@@ -29,69 +28,6 @@
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ip22.h>
-/*
- * Note that mktime uses month from 1 to 12 while rtc_time_to_tm
- * uses 0 to 11.
- */
-unsigned long read_persistent_clock(void)
-{
- unsigned int yrs, mon, day, hrs, min, sec;
- unsigned int save_control;
- unsigned long flags;
-
- spin_lock_irqsave(&rtc_lock, flags);
- save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
- hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;
-
- sec = BCD2BIN(hpc3c0->rtcregs[RTC_SECONDS] & 0xff);
- min = BCD2BIN(hpc3c0->rtcregs[RTC_MINUTES] & 0xff);
- hrs = BCD2BIN(hpc3c0->rtcregs[RTC_HOURS] & 0x3f);
- day = BCD2BIN(hpc3c0->rtcregs[RTC_DATE] & 0xff);
- mon = BCD2BIN(hpc3c0->rtcregs[RTC_MONTH] & 0x1f);
- yrs = BCD2BIN(hpc3c0->rtcregs[RTC_YEAR] & 0xff);
-
- hpc3c0->rtcregs[RTC_CMD] = save_control;
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- if (yrs < 45)
- yrs += 30;
- if ((yrs += 40) < 70)
- yrs += 100;
-
- return mktime(yrs + 1900, mon, day, hrs, min, sec);
-}
-
-int rtc_mips_set_time(unsigned long tim)
-{
- struct rtc_time tm;
- unsigned int save_control;
- unsigned long flags;
-
- rtc_time_to_tm(tim, &tm);
-
- tm.tm_mon += 1; /* tm_mon starts at zero */
- tm.tm_year -= 40;
- if (tm.tm_year >= 100)
- tm.tm_year -= 100;
-
- spin_lock_irqsave(&rtc_lock, flags);
- save_control = hpc3c0->rtcregs[RTC_CMD] & 0xff;
- hpc3c0->rtcregs[RTC_CMD] = save_control | RTC_TE;
-
- hpc3c0->rtcregs[RTC_YEAR] = BIN2BCD(tm.tm_year);
- hpc3c0->rtcregs[RTC_MONTH] = BIN2BCD(tm.tm_mon);
- hpc3c0->rtcregs[RTC_DATE] = BIN2BCD(tm.tm_mday);
- hpc3c0->rtcregs[RTC_HOURS] = BIN2BCD(tm.tm_hour);
- hpc3c0->rtcregs[RTC_MINUTES] = BIN2BCD(tm.tm_min);
- hpc3c0->rtcregs[RTC_SECONDS] = BIN2BCD(tm.tm_sec);
- hpc3c0->rtcregs[RTC_HUNDREDTH_SECOND] = 0;
-
- hpc3c0->rtcregs[RTC_CMD] = save_control;
- spin_unlock_irqrestore(&rtc_lock, flags);
-
- return 0;
-}
-
static unsigned long dosample(void)
{
u32 ct0, ct1;
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index 8b4e854af92..1327c2746fb 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -13,12 +13,12 @@
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/mm.h>
+#include <linux/platform_device.h>
#include <asm/time.h>
#include <asm/pgtable.h>
#include <asm/sgialib.h>
#include <asm/sn/ioc3.h>
-#include <asm/m48t35.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/arch.h>
#include <asm/sn/addrs.h>
@@ -28,51 +28,6 @@
#define TICK_SIZE (tick_nsec / 1000)
-#if 0
-static int set_rtc_mmss(unsigned long nowtime)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- struct m48t35_rtc *rtc;
- nasid_t nid;
-
- nid = get_nasid();
- rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
- IOC3_BYTEBUS_DEV0);
-
- rtc->control |= M48T35_RTC_READ;
- cmos_minutes = BCD2BIN(rtc->min);
- rtc->control &= ~M48T35_RTC_READ;
-
- /*
- * Since we're only adjusting minutes and seconds, don't interfere with
- * hour overflow. This avoids messing with unknown time zones but
- * requires your RTC not to be off by more than 15 minutes
- */
- real_seconds = nowtime % 60;
- real_minutes = nowtime / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- real_seconds = BIN2BCD(real_seconds);
- real_minutes = BIN2BCD(real_minutes);
- rtc->control |= M48T35_RTC_SET;
- rtc->sec = real_seconds;
- rtc->min = real_minutes;
- rtc->control &= ~M48T35_RTC_SET;
- } else {
- printk(KERN_WARNING
- "set_rtc_mmss: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- return retval;
-}
-#endif
-
/* Includes for ioc3_init(). */
#include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h>
@@ -80,37 +35,6 @@ static int set_rtc_mmss(unsigned long nowtime)
#include <asm/sn/sn0/hubio.h>
#include <asm/pci/bridge.h>
-unsigned long read_persistent_clock(void)
-{
- unsigned int year, month, date, hour, min, sec;
- struct m48t35_rtc *rtc;
- nasid_t nid;
-
- nid = get_nasid();
- rtc = (struct m48t35_rtc *)(KL_CONFIG_CH_CONS_INFO(nid)->memory_base +
- IOC3_BYTEBUS_DEV0);
-
- rtc->control |= M48T35_RTC_READ;
- sec = rtc->sec;
- min = rtc->min;
- hour = rtc->hour;
- date = rtc->date;
- month = rtc->month;
- year = rtc->year;
- rtc->control &= ~M48T35_RTC_READ;
-
- sec = BCD2BIN(sec);
- min = BCD2BIN(min);
- hour = BCD2BIN(hour);
- date = BCD2BIN(date);
- month = BCD2BIN(month);
- year = BCD2BIN(year);
-
- year += 1970;
-
- return mktime(year, month, date, hour, min, sec);
-}
-
static void enable_rt_irq(unsigned int irq)
{
}
@@ -286,6 +210,7 @@ void __cpuinit cpu_time_init(void)
void __cpuinit hub_rtc_init(cnodeid_t cnode)
{
+
/*
* We only need to initialize the current node.
* If this is not the current node then it is a cpuless
@@ -301,3 +226,23 @@ void __cpuinit hub_rtc_init(cnodeid_t cnode)
LOCAL_HUB_S(PI_RT_PEND_B, 0);
}
}
+
+static int __init sgi_ip27_rtc_devinit(void)
+{
+ struct resource res;
+
+ memset(&res, 0, sizeof(res));
+ res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base +
+ IOC3_BYTEBUS_DEV0);
+ res.end = res.start + 32767;
+ res.flags = IORESOURCE_MEM;
+
+ return IS_ERR(platform_device_register_simple("rtc-m48t35", -1,
+ &res, 1));
+}
+
+/*
+ * kludge make this a device_initcall after ioc3 resource conflicts
+ * are resolved
+ */
+late_initcall(sgi_ip27_rtc_devinit);
diff --git a/arch/mips/sgi-ip32/ip32-platform.c b/arch/mips/sgi-ip32/ip32-platform.c
index 3d63721e0e8..511e9ff2acf 100644
--- a/arch/mips/sgi-ip32/ip32-platform.c
+++ b/arch/mips/sgi-ip32/ip32-platform.c
@@ -90,6 +90,22 @@ static __init int sgio2btns_devinit(void)
device_initcall(sgio2btns_devinit);
+static struct resource sgio2_cmos_rsrc[] = {
+ {
+ .start = 0x70,
+ .end = 0x71,
+ .flags = IORESOURCE_IO
+ }
+};
+
+static __init int sgio2_cmos_devinit(void)
+{
+ return IS_ERR(platform_device_register_simple("rtc_cmos", -1,
+ sgio2_cmos_rsrc, 1));
+}
+
+device_initcall(sgio2_cmos_devinit);
+
MODULE_AUTHOR("Ralf Baechle <ralf@linux-mips.org>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("8250 UART probe driver for SGI IP32 aka O2");
diff --git a/arch/mips/sgi-ip32/ip32-setup.c b/arch/mips/sgi-ip32/ip32-setup.c
index 1024bf40bd9..c5a5d4a31b4 100644
--- a/arch/mips/sgi-ip32/ip32-setup.c
+++ b/arch/mips/sgi-ip32/ip32-setup.c
@@ -62,11 +62,6 @@ static inline void str2eaddr(unsigned char *ea, unsigned char *str)
}
#endif
-unsigned long read_persistent_clock(void)
-{
- return mc146818_get_cmos_time();
-}
-
/* An arbitrary time; this can be decreased if reliability looks good */
#define WAIT_MS 10
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index 71efd6a28e2..0838155b7a8 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -179,111 +179,6 @@ asmlinkage long sys32_sched_rr_get_interval(pid_t pid,
return ret;
}
-static int
-put_compat_timeval(struct compat_timeval __user *u, struct timeval *t)
-{
- struct compat_timeval t32;
- t32.tv_sec = t->tv_sec;
- t32.tv_usec = t->tv_usec;
- return copy_to_user(u, &t32, sizeof t32);
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
- long usec;
-
- if (__get_user(o->tv_sec, &i->tv_sec))
- return -EFAULT;
- if (__get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-asmlinkage int
-sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- extern void do_gettimeofday(struct timeval *tv);
-
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_compat_timeval(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- extern struct timezone sys_tz;
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage
-int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_ts32(&kts, tv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
- compat_ino_t ino;
- int err;
-
- if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
- !new_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- ino = stat->ino;
- if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
- return -EOVERFLOW;
-
- err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
- err |= put_user(ino, &statbuf->st_ino);
- err |= put_user(stat->mode, &statbuf->st_mode);
- err |= put_user(stat->nlink, &statbuf->st_nlink);
- err |= put_user(0, &statbuf->st_reserved1);
- err |= put_user(0, &statbuf->st_reserved2);
- err |= put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
- err |= put_user(stat->size, &statbuf->st_size);
- err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
- err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
- err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
- err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
- err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
- err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
- err |= put_user(stat->blksize, &statbuf->st_blksize);
- err |= put_user(stat->blocks, &statbuf->st_blocks);
- err |= put_user(0, &statbuf->__unused1);
- err |= put_user(0, &statbuf->__unused2);
- err |= put_user(0, &statbuf->__unused3);
- err |= put_user(0, &statbuf->__unused4);
- err |= put_user(0, &statbuf->__unused5);
- err |= put_user(0, &statbuf->st_fstype); /* not avail */
- err |= put_user(0, &statbuf->st_realdev); /* not avail */
- err |= put_user(0, &statbuf->st_basemode); /* not avail */
- err |= put_user(0, &statbuf->st_spareshort);
- err |= put_user(stat->uid, &statbuf->st_uid);
- err |= put_user(stat->gid, &statbuf->st_gid);
- err |= put_user(0, &statbuf->st_spare4[0]);
- err |= put_user(0, &statbuf->st_spare4[1]);
- err |= put_user(0, &statbuf->st_spare4[2]);
-
- return err;
-}
-
/*** copied from mips64 ***/
/*
* Ooo, nasty. We need here to frob 32-bit unsigned longs to
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 6b5ac38f5a9..c7e59f54881 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -149,8 +149,8 @@
ENTRY_COMP(getrlimit)
ENTRY_COMP(getrusage)
/* struct timeval and timezone are maybe?? consistent wide and narrow */
- ENTRY_DIFF(gettimeofday)
- ENTRY_DIFF(settimeofday)
+ ENTRY_COMP(gettimeofday)
+ ENTRY_COMP(settimeofday)
ENTRY_SAME(getgroups) /* 80 */
ENTRY_SAME(setgroups)
/* struct socketaddr... */
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 587da5e0990..c171f5bcf25 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -415,8 +415,11 @@ config PPC_64K_PAGES
config FORCE_MAX_ZONEORDER
int "Maximum zone order"
+ range 9 64 if PPC_64K_PAGES
default "9" if PPC_64K_PAGES
+ range 13 64 if PPC64 && !PPC_64K_PAGES
default "13" if PPC64 && !PPC_64K_PAGES
+ range 11 64
default "11"
help
The kernel memory allocator divides physically contiguous memory
@@ -806,6 +809,19 @@ config PIN_TLB
endmenu
if PPC64
+config RELOCATABLE
+ bool "Build a relocatable kernel"
+ help
+ This builds a kernel image that is capable of running anywhere
+ in the RMA (real memory area) at any 16k-aligned base address.
+ The kernel is linked as a position-independent executable (PIE)
+ and contains dynamic relocations which are processed early
+ in the bootup process.
+
+ One use is for the kexec on panic case where the recovery kernel
+ must live at a different physical address than the primary
+ kernel.
+
config PAGE_OFFSET
hex
default "0xc000000000000000"
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 4ebc52a19f0..15eb27861fc 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -51,6 +51,11 @@ config FTR_FIXUP_SELFTEST
depends on DEBUG_KERNEL
default n
+config MSI_BITMAP_SELFTEST
+ bool "Run self-tests of the MSI bitmap code."
+ depends on DEBUG_KERNEL
+ default n
+
config XMON
bool "Include xmon kernel debugger"
depends on DEBUG_KERNEL
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index c6be19e9cea..24dd1a37f8f 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -63,7 +63,9 @@ override CC += -m$(CONFIG_WORD_SIZE)
override AR := GNUTARGET=elf$(CONFIG_WORD_SIZE)-powerpc $(AR)
endif
-LDFLAGS_vmlinux := -Bstatic
+LDFLAGS_vmlinux-yy := -Bstatic
+LDFLAGS_vmlinux-$(CONFIG_PPC64)$(CONFIG_RELOCATABLE) := -pie
+LDFLAGS_vmlinux := $(LDFLAGS_vmlinux-yy)
CFLAGS-$(CONFIG_PPC64) := -mminimal-toc -mtraceback=none -mcall-aixdesc
CFLAGS-$(CONFIG_PPC32) := -ffixed-r2 -mmultiple
@@ -102,7 +104,10 @@ endif
KBUILD_CFLAGS += $(call cc-option,-mno-altivec)
# No SPE instruction when building kernel
+# (We use all available options to help semi-broken compilers)
KBUILD_CFLAGS += $(call cc-option,-mno-spe)
+KBUILD_CFLAGS += $(call cc-option,-mspe=no)
+KBUILD_CFLAGS += $(call cc-option,-mabi=no-spe)
# Enable unit-at-a-time mode when possible. It shrinks the
# kernel considerably.
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index 65d1a8454d2..aac1406ccba 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -310,8 +310,11 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb
$(obj)/vmlinux.strip: vmlinux
$(STRIP) -s -R .comment $< -o $@
+# The iseries hypervisor won't take an ET_DYN executable, so this
+# changes the type (byte 17) in the file to ET_EXEC (2).
$(obj)/zImage.iseries: vmlinux
$(STRIP) -s -R .comment $< -o $@
+ printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17
$(obj)/uImage: vmlinux $(wrapperbits)
$(call if_changed,wrap,uboot)
diff --git a/arch/powerpc/boot/addnote.c b/arch/powerpc/boot/addnote.c
index b1e5611b2ab..dcc9ab2ca82 100644
--- a/arch/powerpc/boot/addnote.c
+++ b/arch/powerpc/boot/addnote.c
@@ -11,7 +11,12 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Usage: addnote zImage
+ * Usage: addnote zImage [note.elf]
+ *
+ * If note.elf is supplied, it is the name of an ELF file that contains
+ * an RPA note to use instead of the built-in one. Alternatively, the
+ * note.elf file may be empty, in which case the built-in RPA note is
+ * used (this is to simplify how this is invoked from the wrapper script).
*/
#include <stdio.h>
#include <stdlib.h>
@@ -43,27 +48,29 @@ char rpaname[] = "IBM,RPA-Client-Config";
*/
#define N_RPA_DESCR 8
unsigned int rpanote[N_RPA_DESCR] = {
- 0, /* lparaffinity */
- 64, /* min_rmo_size */
+ 1, /* lparaffinity */
+ 128, /* min_rmo_size */
0, /* min_rmo_percent */
- 40, /* max_pft_size */
+ 46, /* max_pft_size */
1, /* splpar */
-1, /* min_load */
- 0, /* new_mem_def */
- 1, /* ignore_my_client_config */
+ 1, /* new_mem_def */
+ 0, /* ignore_my_client_config */
};
#define ROUNDUP(len) (((len) + 3) & ~3)
unsigned char buf[512];
+unsigned char notebuf[512];
-#define GET_16BE(off) ((buf[off] << 8) + (buf[(off)+1]))
-#define GET_32BE(off) ((GET_16BE(off) << 16) + GET_16BE((off)+2))
+#define GET_16BE(b, off) (((b)[off] << 8) + ((b)[(off)+1]))
+#define GET_32BE(b, off) ((GET_16BE((b), (off)) << 16) + \
+ GET_16BE((b), (off)+2))
-#define PUT_16BE(off, v) (buf[off] = ((v) >> 8) & 0xff, \
- buf[(off) + 1] = (v) & 0xff)
-#define PUT_32BE(off, v) (PUT_16BE((off), (v) >> 16), \
- PUT_16BE((off) + 2, (v)))
+#define PUT_16BE(b, off, v) ((b)[off] = ((v) >> 8) & 0xff, \
+ (b)[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(b, off, v) (PUT_16BE((b), (off), (v) >> 16), \
+ PUT_16BE((b), (off) + 2, (v)))
/* Structure of an ELF file */
#define E_IDENT 0 /* ELF header */
@@ -88,15 +95,71 @@ unsigned char buf[512];
unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
+unsigned char *read_rpanote(const char *fname, int *nnp)
+{
+ int notefd, nr, i;
+ int ph, ps, np;
+ int note, notesize;
+
+ notefd = open(fname, O_RDONLY);
+ if (notefd < 0) {
+ perror(fname);
+ exit(1);
+ }
+ nr = read(notefd, notebuf, sizeof(notebuf));
+ if (nr < 0) {
+ perror("read note");
+ exit(1);
+ }
+ if (nr == 0) /* empty file */
+ return NULL;
+ if (nr < E_HSIZE ||
+ memcmp(&notebuf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0 ||
+ notebuf[E_IDENT+EI_CLASS] != ELFCLASS32 ||
+ notebuf[E_IDENT+EI_DATA] != ELFDATA2MSB)
+ goto notelf;
+ close(notefd);
+
+ /* now look for the RPA-note */
+ ph = GET_32BE(notebuf, E_PHOFF);
+ ps = GET_16BE(notebuf, E_PHENTSIZE);
+ np = GET_16BE(notebuf, E_PHNUM);
+ if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
+ goto notelf;
+
+ for (i = 0; i < np; ++i, ph += ps) {
+ if (GET_32BE(notebuf, ph + PH_TYPE) != PT_NOTE)
+ continue;
+ note = GET_32BE(notebuf, ph + PH_OFFSET);
+ notesize = GET_32BE(notebuf, ph + PH_FILESZ);
+ if (notesize < 34 || note + notesize > nr)
+ continue;
+ if (GET_32BE(notebuf, note) != strlen(rpaname) + 1 ||
+ GET_32BE(notebuf, note + 8) != 0x12759999 ||
+ strcmp((char *)&notebuf[note + 12], rpaname) != 0)
+ continue;
+ /* looks like an RPA note, return it */
+ *nnp = notesize;
+ return &notebuf[note];
+ }
+ /* no RPA note found */
+ return NULL;
+
+ notelf:
+ fprintf(stderr, "%s is not a big-endian 32-bit ELF image\n", fname);
+ exit(1);
+}
+
int
main(int ac, char **av)
{
int fd, n, i;
int ph, ps, np;
int nnote, nnote2, ns;
+ unsigned char *rpap;
- if (ac != 2) {
- fprintf(stderr, "Usage: %s elf-file\n", av[0]);
+ if (ac != 2 && ac != 3) {
+ fprintf(stderr, "Usage: %s elf-file [rpanote.elf]\n", av[0]);
exit(1);
}
fd = open(av[1], O_RDWR);
@@ -107,6 +170,7 @@ main(int ac, char **av)
nnote = 12 + ROUNDUP(strlen(arch) + 1) + sizeof(descr);
nnote2 = 12 + ROUNDUP(strlen(rpaname) + 1) + sizeof(rpanote);
+ rpap = NULL;
n = read(fd, buf, sizeof(buf));
if (n < 0) {
@@ -124,16 +188,19 @@ main(int ac, char **av)
exit(1);
}
- ph = GET_32BE(E_PHOFF);
- ps = GET_16BE(E_PHENTSIZE);
- np = GET_16BE(E_PHNUM);
+ if (ac == 3)
+ rpap = read_rpanote(av[2], &nnote2);
+
+ ph = GET_32BE(buf, E_PHOFF);
+ ps = GET_16BE(buf, E_PHENTSIZE);
+ np = GET_16BE(buf, E_PHNUM);
if (ph < E_HSIZE || ps < PH_HSIZE || np < 1)
goto notelf;
if (ph + (np + 2) * ps + nnote + nnote2 > n)
goto nospace;
for (i = 0; i < np; ++i) {
- if (GET_32BE(ph + PH_TYPE) == PT_NOTE) {
+ if (GET_32BE(buf, ph + PH_TYPE) == PT_NOTE) {
fprintf(stderr, "%s already has a note entry\n",
av[1]);
exit(0);
@@ -148,37 +215,42 @@ main(int ac, char **av)
/* fill in the program header entry */
ns = ph + 2 * ps;
- PUT_32BE(ph + PH_TYPE, PT_NOTE);
- PUT_32BE(ph + PH_OFFSET, ns);
- PUT_32BE(ph + PH_FILESZ, nnote);
+ PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
+ PUT_32BE(buf, ph + PH_OFFSET, ns);
+ PUT_32BE(buf, ph + PH_FILESZ, nnote);
/* fill in the note area we point to */
/* XXX we should probably make this a proper section */
- PUT_32BE(ns, strlen(arch) + 1);
- PUT_32BE(ns + 4, N_DESCR * 4);
- PUT_32BE(ns + 8, 0x1275);
+ PUT_32BE(buf, ns, strlen(arch) + 1);
+ PUT_32BE(buf, ns + 4, N_DESCR * 4);
+ PUT_32BE(buf, ns + 8, 0x1275);
strcpy((char *) &buf[ns + 12], arch);
ns += 12 + strlen(arch) + 1;
for (i = 0; i < N_DESCR; ++i, ns += 4)
- PUT_32BE(ns, descr[i]);
+ PUT_32BE(buf, ns, descr[i]);
/* fill in the second program header entry and the RPA note area */
ph += ps;
- PUT_32BE(ph + PH_TYPE, PT_NOTE);
- PUT_32BE(ph + PH_OFFSET, ns);
- PUT_32BE(ph + PH_FILESZ, nnote2);
+ PUT_32BE(buf, ph + PH_TYPE, PT_NOTE);
+ PUT_32BE(buf, ph + PH_OFFSET, ns);
+ PUT_32BE(buf, ph + PH_FILESZ, nnote2);
/* fill in the note area we point to */
- PUT_32BE(ns, strlen(rpaname) + 1);
- PUT_32BE(ns + 4, sizeof(rpanote));
- PUT_32BE(ns + 8, 0x12759999);
- strcpy((char *) &buf[ns + 12], rpaname);
- ns += 12 + ROUNDUP(strlen(rpaname) + 1);
- for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
- PUT_32BE(ns, rpanote[i]);
+ if (rpap) {
+ /* RPA note supplied in file, just copy the whole thing over */
+ memcpy(buf + ns, rpap, nnote2);
+ } else {
+ PUT_32BE(buf, ns, strlen(rpaname) + 1);
+ PUT_32BE(buf, ns + 4, sizeof(rpanote));
+ PUT_32BE(buf, ns + 8, 0x12759999);
+ strcpy((char *) &buf[ns + 12], rpaname);
+ ns += 12 + ROUNDUP(strlen(rpaname) + 1);
+ for (i = 0; i < N_RPA_DESCR; ++i, ns += 4)
+ PUT_32BE(buf, ns, rpanote[i]);
+ }
/* Update the number of program headers */
- PUT_16BE(E_PHNUM, np + 2);
+ PUT_16BE(buf, E_PHNUM, np + 2);
/* write back */
lseek(fd, (long) 0, SEEK_SET);
diff --git a/arch/powerpc/boot/dtc-src/Makefile.dtc b/arch/powerpc/boot/dtc-src/Makefile.dtc
index d607fdb8df8..6ddf9ecac66 100644
--- a/arch/powerpc/boot/dtc-src/Makefile.dtc
+++ b/arch/powerpc/boot/dtc-src/Makefile.dtc
@@ -5,21 +5,5 @@
#
DTC_SRCS = dtc.c flattree.c fstree.c data.c livetree.c treesource.c srcpos.c \
checks.c
-DTC_EXTRA = dtc.h srcpos.h
-DTC_LEXFILES = dtc-lexer.l
-DTC_BISONFILES = dtc-parser.y
-
-DTC_LEX_SRCS = $(DTC_LEXFILES:%.l=%.lex.c)
-DTC_BISON_SRCS = $(DTC_BISONFILES:%.y=%.tab.c)
-DTC_BISON_INCLUDES = $(DTC_BISONFILES:%.y=%.tab.h)
-
-DTC_GEN_SRCS = $(DTC_LEX_SRCS) $(DTC_BISON_SRCS)
-DTC_GEN_ALL = $(DTC_GEN_SRCS) $(DTC_BISON_INCLUDES)
+DTC_GEN_SRCS = dtc-lexer.lex.c dtc-parser.tab.c
DTC_OBJS = $(DTC_SRCS:%.c=%.o) $(DTC_GEN_SRCS:%.c=%.o)
-
-DTC_CLEANFILES = $(DTC_GEN_ALL)
-
-# We assume the containing Makefile system can do auto-dependencies for most
-# things, but we supply the dependencies on generated header files explicitly
-
-$(addprefix $(DTC_objdir)/,$(DTC_GEN_SRCS:%.c=%.o)): $(addprefix $(DTC_objdir)/,$(DTC_BISON_INCLUDES))
diff --git a/arch/powerpc/boot/dtc-src/checks.c b/arch/powerpc/boot/dtc-src/checks.c
index 2ce961cd414..95485796f25 100644
--- a/arch/powerpc/boot/dtc-src/checks.c
+++ b/arch/powerpc/boot/dtc-src/checks.c
@@ -242,6 +242,42 @@ static void check_duplicate_property_names(struct check *c, struct node *dt,
}
NODE_CHECK(duplicate_property_names, NULL, ERROR);
+#define LOWERCASE "abcdefghijklmnopqrstuvwxyz"
+#define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define DIGITS "0123456789"
+#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-"
+
+static void check_node_name_chars(struct check *c, struct node *dt,
+ struct node *node)
+{
+ int n = strspn(node->name, c->data);
+
+ if (n < strlen(node->name))
+ FAIL(c, "Bad character '%c' in node %s",
+ node->name[n], node->fullpath);
+}
+NODE_CHECK(node_name_chars, PROPNODECHARS "@", ERROR);
+
+static void check_node_name_format(struct check *c, struct node *dt,
+ struct node *node)
+{
+ if (strchr(get_unitname(node), '@'))
+ FAIL(c, "Node %s has multiple '@' characters in name",
+ node->fullpath);
+}
+NODE_CHECK(node_name_format, NULL, ERROR, &node_name_chars);
+
+static void check_property_name_chars(struct check *c, struct node *dt,
+ struct node *node, struct property *prop)
+{
+ int n = strspn(prop->name, c->data);
+
+ if (n < strlen(prop->name))
+ FAIL(c, "Bad character '%c' in property name \"%s\", node %s",
+ prop->name[n], prop->name, node->fullpath);
+}
+PROP_CHECK(property_name_chars, PROPNODECHARS, ERROR);
+
static void check_explicit_phandles(struct check *c, struct node *root,
struct node *node)
{
@@ -280,16 +316,29 @@ NODE_CHECK(explicit_phandles, NULL, ERROR);
static void check_name_properties(struct check *c, struct node *root,
struct node *node)
{
- struct property *prop;
+ struct property **pp, *prop = NULL;
+
+ for (pp = &node->proplist; *pp; pp = &((*pp)->next))
+ if (streq((*pp)->name, "name")) {
+ prop = *pp;
+ break;
+ }
- prop = get_property(node, "name");
if (!prop)
return; /* No name property, that's fine */
if ((prop->val.len != node->basenamelen+1)
- || (memcmp(prop->val.val, node->name, node->basenamelen) != 0))
+ || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) {
FAIL(c, "\"name\" property in %s is incorrect (\"%s\" instead"
" of base node name)", node->fullpath, prop->val.val);
+ } else {
+ /* The name property is correct, and therefore redundant.
+ * Delete it */
+ *pp = prop->next;
+ free(prop->name);
+ data_free(prop->val);
+ free(prop);
+ }
}
CHECK_IS_STRING(name_is_string, "name", ERROR);
NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
@@ -301,23 +350,23 @@ NODE_CHECK(name_properties, NULL, ERROR, &name_is_string);
static void fixup_phandle_references(struct check *c, struct node *dt,
struct node *node, struct property *prop)
{
- struct marker *m = prop->val.markers;
- struct node *refnode;
- cell_t phandle;
-
- for_each_marker_of_type(m, REF_PHANDLE) {
- assert(m->offset + sizeof(cell_t) <= prop->val.len);
-
- refnode = get_node_by_ref(dt, m->ref);
- if (! refnode) {
- FAIL(c, "Reference to non-existent node or label \"%s\"\n",
- m->ref);
- continue;
- }
-
- phandle = get_node_phandle(dt, refnode);
- *((cell_t *)(prop->val.val + m->offset)) = cpu_to_be32(phandle);
- }
+ struct marker *m = prop->val.markers;
+ struct node *refnode;
+ cell_t phandle;
+
+ for_each_marker_of_type(m, REF_PHANDLE) {
+ assert(m->offset + sizeof(cell_t) <= prop->val.len);
+
+ refnode = get_node_by_ref(dt, m->ref);
+ if (! refnode) {
+ FAIL(c, "Reference to non-existent node or label \"%s\"\n",
+ m->ref);
+ continue;
+ }
+
+ phandle = get_node_phandle(dt, refnode);
+ *((cell_t *)(prop->val.val + m->offset)) = cpu_to_fdt32(phandle);
+ }
}
CHECK(phandle_references, NULL, NULL, fixup_phandle_references, NULL, ERROR,
&duplicate_node_names, &explicit_phandles);
@@ -498,6 +547,7 @@ TREE_CHECK(obsolete_chosen_interrupt_controller, NULL, WARN);
static struct check *check_table[] = {
&duplicate_node_names, &duplicate_property_names,
+ &node_name_chars, &node_name_format, &property_name_chars,
&name_is_string, &name_properties,
&explicit_phandles,
&phandle_references, &path_references,
@@ -511,10 +561,7 @@ static struct check *check_table[] = {
&obsolete_chosen_interrupt_controller,
};
-int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys);
-
-void process_checks(int force, struct boot_info *bi,
- int checkflag, int outversion, int boot_cpuid_phys)
+void process_checks(int force, struct boot_info *bi)
{
struct node *dt = bi->dt;
int i;
@@ -537,214 +584,4 @@ void process_checks(int force, struct boot_info *bi,
"output forced\n");
}
}
-
- if (checkflag) {
- if (error) {
- fprintf(stderr, "Warning: Skipping semantic checks due to structural errors\n");
- } else {
- if (!check_semantics(bi->dt, outversion,
- boot_cpuid_phys))
- fprintf(stderr, "Warning: Input tree has semantic errors\n");
- }
- }
-}
-
-/*
- * Semantic check functions
- */
-
-#define ERRMSG(...) if (quiet < 2) fprintf(stderr, "ERROR: " __VA_ARGS__)
-#define WARNMSG(...) if (quiet < 1) fprintf(stderr, "Warning: " __VA_ARGS__)
-
-#define DO_ERR(...) do {ERRMSG(__VA_ARGS__); ok = 0; } while (0)
-
-#define CHECK_HAVE(node, propname) \
- do { \
- if (! (prop = get_property((node), (propname)))) \
- DO_ERR("Missing \"%s\" property in %s\n", (propname), \
- (node)->fullpath); \
- } while (0);
-
-#define CHECK_HAVE_WARN(node, propname) \
- do { \
- if (! (prop = get_property((node), (propname)))) \
- WARNMSG("%s has no \"%s\" property\n", \
- (node)->fullpath, (propname)); \
- } while (0)
-
-#define CHECK_HAVE_STRING(node, propname) \
- do { \
- CHECK_HAVE((node), (propname)); \
- if (prop && !data_is_one_string(prop->val)) \
- DO_ERR("\"%s\" property in %s is not a string\n", \
- (propname), (node)->fullpath); \
- } while (0)
-
-#define CHECK_HAVE_STREQ(node, propname, value) \
- do { \
- CHECK_HAVE_STRING((node), (propname)); \
- if (prop && !streq(prop->val.val, (value))) \
- DO_ERR("%s has wrong %s, %s (should be %s\n", \
- (node)->fullpath, (propname), \
- prop->val.val, (value)); \
- } while (0)
-
-#define CHECK_HAVE_ONECELL(node, propname) \
- do { \
- CHECK_HAVE((node), (propname)); \
- if (prop && (prop->val.len != sizeof(cell_t))) \
- DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
- } while (0)
-
-#define CHECK_HAVE_WARN_ONECELL(node, propname) \
- do { \
- CHECK_HAVE_WARN((node), (propname)); \
- if (prop && (prop->val.len != sizeof(cell_t))) \
- DO_ERR("\"%s\" property in %s has wrong size %d (should be 1 cell)\n", (propname), (node)->fullpath, prop->val.len); \
- } while (0)
-
-#define CHECK_HAVE_WARN_PHANDLE(xnode, propname, root) \
- do { \
- struct node *ref; \
- CHECK_HAVE_WARN_ONECELL((xnode), (propname)); \
- if (prop) {\
- cell_t phandle = propval_cell(prop); \
- if ((phandle == 0) || (phandle == -1)) { \
- DO_ERR("\"%s\" property in %s contains an invalid phandle %x\n", (propname), (xnode)->fullpath, phandle); \
- } else { \
- ref = get_node_by_phandle((root), propval_cell(prop)); \
- if (! ref) \
- DO_ERR("\"%s\" property in %s refers to non-existant phandle %x\n", (propname), (xnode)->fullpath, propval_cell(prop)); \
- } \
- } \
- } while (0)
-
-#define CHECK_HAVE_WARN_STRING(node, propname) \
- do { \
- CHECK_HAVE_WARN((node), (propname)); \
- if (prop && !data_is_one_string(prop->val)) \
- DO_ERR("\"%s\" property in %s is not a string\n", \
- (propname), (node)->fullpath); \
- } while (0)
-
-static int check_root(struct node *root)
-{
- struct property *prop;
- int ok = 1;
-
- CHECK_HAVE_STRING(root, "model");
- CHECK_HAVE_WARN(root, "compatible");
-
- return ok;
-}
-
-static int check_cpus(struct node *root, int outversion, int boot_cpuid_phys)
-{
- struct node *cpus, *cpu;
- struct property *prop;
- struct node *bootcpu = NULL;
- int ok = 1;
-
- cpus = get_subnode(root, "cpus");
- if (! cpus) {
- ERRMSG("Missing /cpus node\n");
- return 0;
- }
-
- if (cpus->addr_cells != 1)
- DO_ERR("%s has bad #address-cells value %d (should be 1)\n",
- cpus->fullpath, cpus->addr_cells);
- if (cpus->size_cells != 0)
- DO_ERR("%s has bad #size-cells value %d (should be 0)\n",
- cpus->fullpath, cpus->size_cells);
-
- for_each_child(cpus, cpu) {
- CHECK_HAVE_STREQ(cpu, "device_type", "cpu");
-
- CHECK_HAVE_ONECELL(cpu, "reg");
- if (prop) {
- cell_t unitnum;
- char *eptr;
-
- unitnum = strtol(get_unitname(cpu), &eptr, 16);
- if (*eptr) {
- WARNMSG("%s has bad format unit name %s (should be CPU number\n",
- cpu->fullpath, get_unitname(cpu));
- } else if (unitnum != propval_cell(prop)) {
- WARNMSG("%s unit name \"%s\" does not match \"reg\" property <%x>\n",
- cpu->fullpath, get_unitname(cpu),
- propval_cell(prop));
- }
- }
-
-/* CHECK_HAVE_ONECELL(cpu, "d-cache-line-size"); */
-/* CHECK_HAVE_ONECELL(cpu, "i-cache-line-size"); */
- CHECK_HAVE_ONECELL(cpu, "d-cache-size");
- CHECK_HAVE_ONECELL(cpu, "i-cache-size");
-
- CHECK_HAVE_WARN_ONECELL(cpu, "clock-frequency");
- CHECK_HAVE_WARN_ONECELL(cpu, "timebase-frequency");
-
- prop = get_property(cpu, "linux,boot-cpu");
- if (prop) {
- if (prop->val.len)
- WARNMSG("\"linux,boot-cpu\" property in %s is non-empty\n",
- cpu->fullpath);
- if (bootcpu)
- DO_ERR("Multiple boot cpus (%s and %s)\n",
- bootcpu->fullpath, cpu->fullpath);
- else
- bootcpu = cpu;
- }
- }
-
- if (outversion < 2) {
- if (! bootcpu)
- WARNMSG("No cpu has \"linux,boot-cpu\" property\n");
- } else {
- if (bootcpu)
- WARNMSG("\"linux,boot-cpu\" property is deprecated in blob version 2 or higher\n");
- if (boot_cpuid_phys == 0xfeedbeef)
- WARNMSG("physical boot CPU not set. Use -b option to set\n");
- }
-
- return ok;
-}
-
-static int check_memory(struct node *root)
-{
- struct node *mem;
- struct property *prop;
- int nnodes = 0;
- int ok = 1;
-
- for_each_child(root, mem) {
- if (! strneq(mem->name, "memory", mem->basenamelen))
- continue;
-
- nnodes++;
-
- CHECK_HAVE_STREQ(mem, "device_type", "memory");
- CHECK_HAVE(mem, "reg");
- }
-
- if (nnodes == 0) {
- ERRMSG("No memory nodes\n");
- return 0;
- }
-
- return ok;
-}
-
-int check_semantics(struct node *dt, int outversion, int boot_cpuid_phys)
-{
- int ok = 1;
-
- ok = ok && check_root(dt);
- ok = ok && check_cpus(dt, outversion, boot_cpuid_phys);
- ok = ok && check_memory(dt);
- if (! ok)
- return 0;
-
- return 1;
}
diff --git a/arch/powerpc/boot/dtc-src/data.c b/arch/powerpc/boot/dtc-src/data.c
index a94718c731a..dd2e3d39d4c 100644
--- a/arch/powerpc/boot/dtc-src/data.c
+++ b/arch/powerpc/boot/dtc-src/data.c
@@ -32,8 +32,6 @@ void data_free(struct data d)
m = nm;
}
- assert(!d.val || d.asize);
-
if (d.val)
free(d.val);
}
@@ -43,9 +41,6 @@ struct data data_grow_for(struct data d, int xlen)
struct data nd;
int newsize;
- /* we must start with an allocated datum */
- assert(!d.val || d.asize);
-
if (xlen == 0)
return d;
@@ -56,11 +51,8 @@ struct data data_grow_for(struct data d, int xlen)
while ((d.len + xlen) > newsize)
newsize *= 2;
- nd.asize = newsize;
nd.val = xrealloc(d.val, newsize);
- assert(nd.asize >= (d.len + xlen));
-
return nd;
}
@@ -83,16 +75,11 @@ static char get_oct_char(const char *s, int *i)
long val;
x[3] = '\0';
- x[0] = s[(*i)];
- if (x[0]) {
- x[1] = s[(*i)+1];
- if (x[1])
- x[2] = s[(*i)+2];
- }
+ strncpy(x, s + *i, 3);
val = strtol(x, &endx, 8);
- if ((endx - x) == 0)
- fprintf(stderr, "Empty \\nnn escape\n");
+
+ assert(endx > x);
(*i) += endx - x;
return val;
@@ -105,13 +92,11 @@ static char get_hex_char(const char *s, int *i)
long val;
x[2] = '\0';
- x[0] = s[(*i)];
- if (x[0])
- x[1] = s[(*i)+1];
+ strncpy(x, s + *i, 2);
val = strtol(x, &endx, 16);
- if ((endx - x) == 0)
- fprintf(stderr, "Empty \\x escape\n");
+ if (!(endx > x))
+ die("\\x used with no following hex digits\n");
(*i) += endx - x;
return val;
@@ -182,14 +167,29 @@ struct data data_copy_escape_string(const char *s, int len)
return d;
}
-struct data data_copy_file(FILE *f, size_t len)
+struct data data_copy_file(FILE *f, size_t maxlen)
{
- struct data d;
+ struct data d = empty_data;
- d = data_grow_for(empty_data, len);
+ while (!feof(f) && (d.len < maxlen)) {
+ size_t chunksize, ret;
- d.len = len;
- fread(d.val, len, 1, f);
+ if (maxlen == -1)
+ chunksize = 4096;
+ else
+ chunksize = maxlen - d.len;
+
+ d = data_grow_for(d, chunksize);
+ ret = fread(d.val + d.len, 1, chunksize, f);
+
+ if (ferror(f))
+ die("Error reading file into data: %s", strerror(errno));
+
+ if (d.len + ret < d.len)
+ die("Overflow reading file into data\n");
+
+ d.len += ret;
+ }
return d;
}
@@ -247,7 +247,7 @@ struct data data_merge(struct data d1, struct data d2)
struct data data_append_cell(struct data d, cell_t word)
{
- cell_t beword = cpu_to_be32(word);
+ cell_t beword = cpu_to_fdt32(word);
return data_append_data(d, &beword, sizeof(beword));
}
@@ -256,15 +256,15 @@ struct data data_append_re(struct data d, const struct fdt_reserve_entry *re)
{
struct fdt_reserve_entry bere;
- bere.address = cpu_to_be64(re->address);
- bere.size = cpu_to_be64(re->size);
+ bere.address = cpu_to_fdt64(re->address);
+ bere.size = cpu_to_fdt64(re->size);
return data_append_data(d, &bere, sizeof(bere));
}
-struct data data_append_addr(struct data d, u64 addr)
+struct data data_append_addr(struct data d, uint64_t addr)
{
- u64 beaddr = cpu_to_be64(addr);
+ uint64_t beaddr = cpu_to_fdt64(addr);
return data_append_data(d, &beaddr, sizeof(beaddr));
}
diff --git a/arch/powerpc/boot/dtc-src/dtc-lexer.l b/arch/powerpc/boot/dtc-src/dtc-lexer.l
index c811b221b31..44dbfd3f097 100644
--- a/arch/powerpc/boot/dtc-src/dtc-lexer.l
+++ b/arch/powerpc/boot/dtc-src/dtc-lexer.l
@@ -28,6 +28,10 @@
PROPNODECHAR [a-zA-Z0-9,._+*#?@-]
PATHCHAR ({PROPNODECHAR}|[/])
LABEL [a-zA-Z_][a-zA-Z0-9_]*
+STRING \"([^\\"]|\\.)*\"
+WS [[:space:]]
+COMMENT "/*"([^*]|\*+[^*/])*\*+"/"
+LINECOMMENT "//".*\n
%{
#include "dtc.h"
@@ -52,29 +56,26 @@ static int dts_version; /* = 0 */
DPRINT("<V1>\n"); \
BEGIN(V1); \
}
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
%}
%%
-<*>"/include/" BEGIN(INCLUDE);
-
-<INCLUDE>\"[^"\n]*\" {
- yytext[strlen(yytext) - 1] = 0;
- if (!push_input_file(yytext + 1)) {
- /* Some unrecoverable error.*/
- exit(1);
- }
- BEGIN_DEFAULT();
+<*>"/include/"{WS}*{STRING} {
+ char *name = strchr(yytext, '\"') + 1;
+ yytext[yyleng-1] = '\0';
+ push_input_file(name);
}
-
<*><<EOF>> {
if (!pop_input_file()) {
yyterminate();
}
}
-<*>\"([^\\"]|\\.)*\" {
- yylloc.filenum = srcpos_filenum;
+<*>{STRING} {
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
@@ -84,7 +85,7 @@ static int dts_version; /* = 0 */
}
<*>"/dts-v1/" {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /dts-v1/\n");
dts_version = 1;
@@ -93,7 +94,7 @@ static int dts_version; /* = 0 */
}
<*>"/memreserve/" {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
@@ -101,7 +102,7 @@ static int dts_version; /* = 0 */
}
<*>{LABEL}: {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext);
yylval.labelref = strdup(yytext);
@@ -110,7 +111,7 @@ static int dts_version; /* = 0 */
}
<INITIAL>[bodh]# {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
if (*yytext == 'b')
yylval.cbase = 2;
@@ -125,7 +126,7 @@ static int dts_version; /* = 0 */
}
<INITIAL>[0-9a-fA-F]+ {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
@@ -133,7 +134,7 @@ static int dts_version; /* = 0 */
}
<V1>[0-9]+|0[xX][0-9a-fA-F]+ {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
@@ -141,7 +142,7 @@ static int dts_version; /* = 0 */
}
\&{LABEL} { /* label reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
@@ -149,7 +150,7 @@ static int dts_version; /* = 0 */
}
"&{/"{PATHCHAR}+\} { /* new-style path reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
@@ -158,7 +159,7 @@ static int dts_version; /* = 0 */
}
<INITIAL>"&/"{PATHCHAR}+ { /* old-style path reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
@@ -166,7 +167,7 @@ static int dts_version; /* = 0 */
}
<BYTESTRING>[0-9a-fA-F]{2} {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
@@ -174,7 +175,7 @@ static int dts_version; /* = 0 */
}
<BYTESTRING>"]" {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
@@ -182,7 +183,7 @@ static int dts_version; /* = 0 */
}
<PROPNODENAME>{PROPNODECHAR}+ {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = strdup(yytext);
@@ -190,20 +191,19 @@ static int dts_version; /* = 0 */
return DT_PROPNODENAME;
}
-
-<*>[[:space:]]+ /* eat whitespace */
-
-<*>"/*"([^*]|\*+[^*/])*\*+"/" {
- yylloc.filenum = srcpos_filenum;
+"/incbin/" {
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
- DPRINT("Comment: %s\n", yytext);
- /* eat comments */
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
}
-<*>"//".*\n /* eat line comments */
+<*>{WS}+ /* eat whitespace */
+<*>{COMMENT}+ /* eat C-style comments */
+<*>{LINECOMMENT}+ /* eat C++-style comments */
<*>. {
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
@@ -227,14 +227,13 @@ static int dts_version; /* = 0 */
*/
struct incl_file {
- int filenum;
- FILE *file;
+ struct dtc_file *file;
YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno;
struct incl_file *prev;
};
-struct incl_file *incl_file_stack;
+static struct incl_file *incl_file_stack;
/*
@@ -245,36 +244,34 @@ struct incl_file *incl_file_stack;
static int incl_depth = 0;
-int push_input_file(const char *filename)
+static void push_input_file(const char *filename)
{
- FILE *f;
struct incl_file *incl_file;
+ struct dtc_file *newfile;
+ struct search_path search, *searchptr = NULL;
- if (!filename) {
- yyerror("No include file name given.");
- return 0;
- }
+ assert(filename);
- if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
- yyerror("Includes nested too deeply");
- return 0;
+ if (incl_depth++ >= MAX_INCLUDE_DEPTH)
+ die("Includes nested too deeply");
+
+ if (srcpos_file) {
+ search.dir = srcpos_file->dir;
+ search.next = NULL;
+ search.prev = NULL;
+ searchptr = &search;
}
- f = dtc_open_file(filename);
+ newfile = dtc_open_file(filename, searchptr);
- incl_file = malloc(sizeof(struct incl_file));
- if (!incl_file) {
- yyerror("Can not allocate include file space.");
- return 0;
- }
+ incl_file = xmalloc(sizeof(struct incl_file));
/*
* Save current context.
*/
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno;
- incl_file->filenum = srcpos_filenum;
- incl_file->file = yyin;
+ incl_file->file = srcpos_file;
incl_file->prev = incl_file_stack;
incl_file_stack = incl_file;
@@ -282,23 +279,21 @@ int push_input_file(const char *filename)
/*
* Establish new context.
*/
- srcpos_filenum = lookup_file_name(filename, 0);
+ srcpos_file = newfile;
yylineno = 1;
- yyin = f;
+ yyin = newfile->file;
yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE));
-
- return 1;
}
-int pop_input_file(void)
+static int pop_input_file(void)
{
struct incl_file *incl_file;
if (incl_file_stack == 0)
return 0;
- fclose(yyin);
+ dtc_close_file(srcpos_file);
/*
* Pop.
@@ -313,16 +308,13 @@ int pop_input_file(void)
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno;
- srcpos_filenum = incl_file->filenum;
- yyin = incl_file->file;
+ srcpos_file = incl_file->file;
+ yyin = incl_file->file ? incl_file->file->file : NULL;
/*
* Free old state.
*/
free(incl_file);
- if (YY_CURRENT_BUFFER == 0)
- return 0;
-
return 1;
}
diff --git a/arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped b/arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped
index d0f742460f9..ac392cb040f 100644
--- a/arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped
+++ b/arch/powerpc/boot/dtc-src/dtc-lexer.lex.c_shipped
@@ -9,7 +9,7 @@
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 33
+#define YY_FLEX_SUBMINOR_VERSION 34
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
@@ -31,7 +31,7 @@
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-#if __STDC_VERSION__ >= 199901L
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
@@ -94,11 +94,12 @@ typedef unsigned int flex_uint32_t;
#else /* ! __cplusplus */
-#if __STDC__
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
#define YY_USE_CONST
-#endif /* __STDC__ */
+#endif /* defined (__STDC__) */
#endif /* ! __cplusplus */
#ifdef YY_USE_CONST
@@ -194,11 +195,13 @@ extern FILE *yyin, *yyout;
/* The following is because we cannot portably get our hands on size_t
* (without autoconf's help, which isn't available because we want
* flex-generated scanners to compile on their own).
+ * Given that the standard has decreed that size_t exists since 1989,
+ * I guess we can afford to depend on it. Manoj.
*/
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
-typedef unsigned int yy_size_t;
+typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
@@ -349,7 +352,7 @@ void yyfree (void * );
/* Begin user sect3 */
-#define yywrap() 1
+#define yywrap(n) 1
#define YY_SKIP_YYWRAP
typedef unsigned char YY_CHAR;
@@ -389,19 +392,20 @@ struct yy_trans_info
flex_int32_t yy_verify;
flex_int32_t yy_nxt;
};
-static yyconst flex_int16_t yy_accept[94] =
+static yyconst flex_int16_t yy_accept[104] =
{ 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 21, 19, 16, 16, 19, 19, 19, 8, 8, 19,
- 8, 19, 19, 19, 19, 14, 15, 15, 19, 9,
- 9, 16, 0, 3, 0, 0, 10, 0, 0, 0,
- 0, 0, 0, 8, 8, 6, 0, 7, 0, 2,
- 0, 13, 13, 15, 15, 9, 0, 12, 10, 0,
- 0, 0, 0, 18, 0, 0, 0, 2, 9, 0,
- 17, 0, 0, 0, 11, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 4, 0, 0, 1, 0, 0,
- 0, 5, 0
-
+ 21, 19, 16, 16, 19, 19, 19, 7, 7, 19,
+ 7, 19, 19, 19, 19, 13, 14, 14, 19, 8,
+ 8, 16, 0, 2, 0, 0, 9, 0, 0, 0,
+ 0, 0, 0, 7, 7, 5, 0, 6, 0, 12,
+ 12, 14, 14, 8, 0, 11, 9, 0, 0, 0,
+ 0, 18, 0, 0, 0, 0, 8, 0, 17, 0,
+ 0, 0, 0, 0, 10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 3, 15,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+
+ 0, 4, 0
} ;
static yyconst flex_int32_t yy_ec[256] =
@@ -444,122 +448,126 @@ static yyconst flex_int32_t yy_meta[36] =
7, 7, 7, 8, 1
} ;
-static yyconst flex_int16_t yy_base[107] =
+static yyconst flex_int16_t yy_base[117] =
{ 0,
- 0, 0, 32, 0, 53, 0, 76, 0, 108, 111,
- 280, 288, 37, 39, 33, 36, 106, 0, 123, 146,
- 255, 251, 45, 0, 159, 288, 0, 53, 108, 172,
- 114, 127, 158, 288, 245, 0, 0, 234, 235, 236,
- 197, 195, 199, 0, 0, 288, 0, 288, 160, 288,
- 183, 288, 0, 0, 183, 182, 0, 0, 0, 0,
- 204, 189, 207, 288, 179, 187, 180, 194, 0, 171,
- 288, 196, 178, 174, 288, 169, 169, 177, 165, 153,
- 143, 155, 137, 118, 288, 122, 42, 288, 36, 36,
- 40, 288, 288, 212, 218, 223, 229, 234, 239, 245,
-
- 251, 255, 262, 270, 275, 280
+ 0, 0, 30, 0, 44, 0, 67, 0, 97, 105,
+ 302, 303, 35, 44, 40, 94, 112, 0, 129, 152,
+ 296, 295, 159, 0, 176, 303, 0, 116, 95, 165,
+ 49, 46, 102, 303, 296, 0, 0, 288, 290, 293,
+ 264, 266, 270, 0, 0, 303, 0, 303, 264, 303,
+ 0, 0, 195, 101, 0, 0, 0, 0, 284, 125,
+ 277, 265, 225, 230, 216, 218, 0, 202, 224, 221,
+ 217, 107, 196, 188, 303, 206, 179, 186, 178, 185,
+ 183, 162, 161, 150, 169, 160, 145, 125, 303, 303,
+ 137, 109, 190, 103, 203, 167, 108, 197, 303, 123,
+
+ 29, 303, 303, 215, 221, 226, 229, 234, 240, 246,
+ 250, 257, 265, 270, 275, 282
} ;
-static yyconst flex_int16_t yy_def[107] =
+static yyconst flex_int16_t yy_def[117] =
{ 0,
- 93, 1, 1, 3, 3, 5, 93, 7, 3, 3,
- 93, 93, 93, 93, 94, 95, 93, 96, 93, 19,
- 19, 20, 97, 98, 20, 93, 99, 100, 95, 93,
- 93, 93, 94, 93, 94, 101, 102, 93, 103, 104,
- 93, 93, 93, 96, 19, 93, 20, 93, 97, 93,
- 97, 93, 20, 99, 100, 93, 105, 101, 102, 106,
- 103, 103, 104, 93, 93, 93, 93, 94, 105, 106,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 0, 93, 93, 93, 93, 93, 93, 93,
-
- 93, 93, 93, 93, 93, 93
+ 103, 1, 1, 3, 3, 5, 103, 7, 3, 3,
+ 103, 103, 103, 103, 104, 105, 103, 106, 103, 19,
+ 19, 20, 103, 107, 20, 103, 108, 109, 105, 103,
+ 103, 103, 104, 103, 104, 110, 111, 103, 112, 113,
+ 103, 103, 103, 106, 19, 103, 20, 103, 103, 103,
+ 20, 108, 109, 103, 114, 110, 111, 115, 112, 112,
+ 113, 103, 103, 103, 103, 103, 114, 115, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 116, 103, 116, 103, 116,
+
+ 103, 103, 0, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103
} ;
-static yyconst flex_int16_t yy_nxt[324] =
+static yyconst flex_int16_t yy_nxt[339] =
{ 0,
12, 13, 14, 15, 12, 16, 12, 12, 12, 17,
18, 18, 18, 12, 19, 20, 20, 12, 12, 21,
19, 21, 19, 22, 20, 20, 20, 20, 20, 20,
- 20, 20, 20, 12, 12, 23, 34, 12, 32, 32,
- 32, 32, 12, 12, 12, 36, 20, 33, 50, 92,
- 35, 20, 20, 20, 20, 20, 15, 54, 91, 54,
- 54, 54, 51, 24, 24, 24, 46, 25, 90, 38,
- 89, 26, 25, 25, 25, 25, 12, 13, 14, 15,
- 27, 12, 27, 27, 27, 17, 27, 27, 27, 12,
- 28, 28, 28, 12, 12, 28, 28, 28, 28, 28,
-
- 28, 28, 28, 28, 28, 28, 28, 28, 28, 12,
- 12, 15, 39, 29, 15, 40, 29, 93, 30, 31,
- 31, 30, 31, 31, 56, 56, 56, 41, 32, 32,
- 42, 88, 43, 45, 45, 45, 46, 45, 47, 47,
- 87, 38, 45, 45, 45, 45, 47, 47, 47, 47,
- 47, 47, 47, 47, 47, 47, 47, 47, 47, 86,
- 47, 34, 33, 50, 85, 47, 47, 47, 47, 53,
- 53, 53, 84, 53, 83, 35, 82, 51, 53, 53,
- 53, 53, 56, 56, 56, 93, 68, 54, 57, 54,
- 54, 54, 56, 56, 56, 62, 46, 34, 71, 81,
-
- 80, 79, 78, 77, 76, 75, 74, 73, 72, 64,
- 62, 35, 33, 33, 33, 33, 33, 33, 33, 33,
- 37, 67, 66, 37, 37, 37, 44, 65, 44, 49,
- 49, 49, 49, 49, 49, 49, 49, 52, 64, 52,
- 54, 62, 54, 60, 54, 54, 55, 93, 55, 55,
- 55, 55, 58, 58, 58, 48, 58, 58, 59, 48,
- 59, 59, 61, 61, 61, 61, 61, 61, 61, 61,
- 63, 63, 63, 63, 63, 63, 63, 63, 69, 93,
- 69, 70, 70, 70, 93, 70, 70, 11, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
-
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93
+ 20, 20, 20, 12, 12, 12, 32, 32, 102, 23,
+ 12, 12, 12, 34, 20, 32, 32, 32, 32, 20,
+ 20, 20, 20, 20, 24, 24, 24, 35, 25, 54,
+ 54, 54, 26, 25, 25, 25, 25, 12, 13, 14,
+ 15, 27, 12, 27, 27, 27, 23, 27, 27, 27,
+ 12, 28, 28, 28, 12, 12, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+
+ 12, 12, 29, 36, 103, 34, 17, 30, 31, 31,
+ 29, 54, 54, 54, 17, 30, 31, 31, 39, 35,
+ 52, 40, 52, 52, 52, 103, 78, 38, 38, 46,
+ 101, 60, 79, 41, 69, 97, 42, 94, 43, 45,
+ 45, 45, 46, 45, 47, 47, 93, 92, 45, 45,
+ 45, 45, 47, 47, 47, 47, 47, 47, 47, 47,
+ 47, 47, 47, 47, 47, 39, 47, 91, 40, 90,
+ 99, 47, 47, 47, 47, 54, 54, 54, 89, 88,
+ 41, 55, 87, 49, 100, 43, 51, 51, 51, 86,
+ 51, 95, 95, 96, 85, 51, 51, 51, 51, 52,
+
+ 99, 52, 52, 52, 95, 95, 96, 84, 46, 83,
+ 82, 81, 39, 79, 100, 33, 33, 33, 33, 33,
+ 33, 33, 33, 37, 80, 77, 37, 37, 37, 44,
+ 40, 44, 50, 76, 50, 52, 75, 52, 74, 52,
+ 52, 53, 73, 53, 53, 53, 53, 56, 56, 56,
+ 72, 56, 56, 57, 71, 57, 57, 59, 59, 59,
+ 59, 59, 59, 59, 59, 61, 61, 61, 61, 61,
+ 61, 61, 61, 67, 70, 67, 68, 68, 68, 62,
+ 68, 68, 98, 98, 98, 98, 98, 98, 98, 98,
+ 60, 66, 65, 64, 63, 62, 60, 58, 103, 48,
+
+ 48, 103, 11, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103
} ;
-static yyconst flex_int16_t yy_chk[324] =
+static yyconst flex_int16_t yy_chk[339] =
{ 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 3, 15, 3, 13, 13,
- 14, 14, 3, 3, 3, 16, 3, 23, 23, 91,
- 15, 3, 3, 3, 3, 3, 5, 28, 90, 28,
- 28, 28, 23, 5, 5, 5, 28, 5, 89, 16,
- 87, 5, 5, 5, 5, 5, 7, 7, 7, 7,
+ 1, 1, 1, 1, 1, 3, 13, 13, 101, 3,
+ 3, 3, 3, 15, 3, 14, 14, 32, 32, 3,
+ 3, 3, 3, 3, 5, 5, 5, 15, 5, 31,
+ 31, 31, 5, 5, 5, 5, 5, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
-
7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 9, 17, 9, 10, 17, 10, 29, 9, 9,
- 9, 10, 10, 10, 31, 31, 31, 17, 32, 32,
- 17, 86, 17, 19, 19, 19, 19, 19, 19, 19,
- 84, 29, 19, 19, 19, 19, 19, 19, 19, 19,
- 19, 19, 19, 19, 19, 19, 20, 20, 20, 83,
- 20, 33, 49, 49, 82, 20, 20, 20, 20, 25,
- 25, 25, 81, 25, 80, 33, 79, 49, 25, 25,
- 25, 25, 30, 30, 30, 51, 51, 55, 30, 55,
- 55, 55, 56, 56, 56, 62, 55, 68, 62, 78,
-
- 77, 76, 74, 73, 72, 70, 67, 66, 65, 63,
- 61, 68, 94, 94, 94, 94, 94, 94, 94, 94,
- 95, 43, 42, 95, 95, 95, 96, 41, 96, 97,
- 97, 97, 97, 97, 97, 97, 97, 98, 40, 98,
- 99, 39, 99, 38, 99, 99, 100, 35, 100, 100,
- 100, 100, 101, 101, 101, 22, 101, 101, 102, 21,
- 102, 102, 103, 103, 103, 103, 103, 103, 103, 103,
- 104, 104, 104, 104, 104, 104, 104, 104, 105, 11,
- 105, 106, 106, 106, 0, 106, 106, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
-
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
- 93, 93, 93
+
+ 7, 7, 9, 16, 29, 33, 9, 9, 9, 9,
+ 10, 54, 54, 54, 10, 10, 10, 10, 17, 33,
+ 28, 17, 28, 28, 28, 100, 72, 16, 29, 28,
+ 97, 60, 72, 17, 60, 94, 17, 92, 17, 19,
+ 19, 19, 19, 19, 19, 19, 91, 88, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 20, 20, 20, 23, 20, 87, 23, 86,
+ 96, 20, 20, 20, 20, 30, 30, 30, 85, 84,
+ 23, 30, 83, 23, 96, 23, 25, 25, 25, 82,
+ 25, 93, 93, 93, 81, 25, 25, 25, 25, 53,
+
+ 98, 53, 53, 53, 95, 95, 95, 80, 53, 79,
+ 78, 77, 76, 74, 98, 104, 104, 104, 104, 104,
+ 104, 104, 104, 105, 73, 71, 105, 105, 105, 106,
+ 70, 106, 107, 69, 107, 108, 68, 108, 66, 108,
+ 108, 109, 65, 109, 109, 109, 109, 110, 110, 110,
+ 64, 110, 110, 111, 63, 111, 111, 112, 112, 112,
+ 112, 112, 112, 112, 112, 113, 113, 113, 113, 113,
+ 113, 113, 113, 114, 62, 114, 115, 115, 115, 61,
+ 115, 115, 116, 116, 116, 116, 116, 116, 116, 116,
+ 59, 49, 43, 42, 41, 40, 39, 38, 35, 22,
+
+ 21, 11, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103
} ;
/* Table of booleans, true if rule could match eol. */
static yyconst flex_int32_t yy_rule_can_match_eol[21] =
{ 0,
-0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
+1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, };
static yy_state_type yy_last_accepting_state;
@@ -600,7 +608,7 @@ char *yytext;
-#line 33 "dtc-lexer.l"
+#line 37 "dtc-lexer.l"
#include "dtc.h"
#include "srcpos.h"
#include "dtc-parser.tab.h"
@@ -623,7 +631,10 @@ static int dts_version; /* = 0 */
DPRINT("<V1>\n"); \
BEGIN(V1); \
}
-#line 627 "dtc-lexer.lex.c"
+
+static void push_input_file(const char *filename);
+static int pop_input_file(void);
+#line 638 "dtc-lexer.lex.c"
#define INITIAL 0
#define INCLUDE 1
@@ -685,7 +696,7 @@ static int input (void );
/* This used to be an fputs(), but since the string might contain NUL's,
* we now use fwrite().
*/
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#define ECHO fwrite( yytext, yyleng, 1, yyout )
#endif
/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
@@ -696,7 +707,7 @@ static int input (void );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- size_t n; \
+ int n; \
for ( n = 0; n < max_size && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
@@ -778,9 +789,9 @@ YY_DECL
register char *yy_cp, *yy_bp;
register int yy_act;
-#line 57 "dtc-lexer.l"
+#line 64 "dtc-lexer.l"
-#line 784 "dtc-lexer.lex.c"
+#line 795 "dtc-lexer.lex.c"
if ( !(yy_init) )
{
@@ -833,13 +844,13 @@ yy_match:
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 94 )
+ if ( yy_current_state >= 104 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
++yy_cp;
}
- while ( yy_base[yy_current_state] != 288 );
+ while ( yy_base[yy_current_state] != 303 );
yy_find_action:
yy_act = yy_accept[yy_current_state];
@@ -874,20 +885,13 @@ do_action: /* This label is used only to access EOF actions. */
goto yy_find_action;
case 1:
+/* rule 1 can match eol */
YY_RULE_SETUP
-#line 58 "dtc-lexer.l"
-BEGIN(INCLUDE);
- YY_BREAK
-case 2:
-YY_RULE_SETUP
-#line 60 "dtc-lexer.l"
+#line 65 "dtc-lexer.l"
{
- yytext[strlen(yytext) - 1] = 0;
- if (!push_input_file(yytext + 1)) {
- /* Some unrecoverable error.*/
- exit(1);
- }
- BEGIN_DEFAULT();
+ char *name = strchr(yytext, '\"') + 1;
+ yytext[yyleng-1] = '\0';
+ push_input_file(name);
}
YY_BREAK
case YY_STATE_EOF(INITIAL):
@@ -895,19 +899,19 @@ case YY_STATE_EOF(INCLUDE):
case YY_STATE_EOF(BYTESTRING):
case YY_STATE_EOF(PROPNODENAME):
case YY_STATE_EOF(V1):
-#line 70 "dtc-lexer.l"
+#line 71 "dtc-lexer.l"
{
if (!pop_input_file()) {
yyterminate();
}
}
YY_BREAK
-case 3:
-/* rule 3 can match eol */
+case 2:
+/* rule 2 can match eol */
YY_RULE_SETUP
-#line 76 "dtc-lexer.l"
+#line 77 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("String: %s\n", yytext);
yylval.data = data_copy_escape_string(yytext+1,
@@ -916,11 +920,11 @@ YY_RULE_SETUP
return DT_STRING;
}
YY_BREAK
-case 4:
+case 3:
YY_RULE_SETUP
-#line 86 "dtc-lexer.l"
+#line 87 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /dts-v1/\n");
dts_version = 1;
@@ -928,22 +932,22 @@ YY_RULE_SETUP
return DT_V1;
}
YY_BREAK
-case 5:
+case 4:
YY_RULE_SETUP
-#line 95 "dtc-lexer.l"
+#line 96 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Keyword: /memreserve/\n");
BEGIN_DEFAULT();
return DT_MEMRESERVE;
}
YY_BREAK
-case 6:
+case 5:
YY_RULE_SETUP
-#line 103 "dtc-lexer.l"
+#line 104 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Label: %s\n", yytext);
yylval.labelref = strdup(yytext);
@@ -951,11 +955,11 @@ YY_RULE_SETUP
return DT_LABEL;
}
YY_BREAK
-case 7:
+case 6:
YY_RULE_SETUP
-#line 112 "dtc-lexer.l"
+#line 113 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
if (*yytext == 'b')
yylval.cbase = 2;
@@ -969,44 +973,44 @@ YY_RULE_SETUP
return DT_BASE;
}
YY_BREAK
-case 8:
+case 7:
YY_RULE_SETUP
-#line 127 "dtc-lexer.l"
+#line 128 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LEGACYLITERAL;
}
YY_BREAK
-case 9:
+case 8:
YY_RULE_SETUP
-#line 135 "dtc-lexer.l"
+#line 136 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.literal = strdup(yytext);
DPRINT("Literal: '%s'\n", yylval.literal);
return DT_LITERAL;
}
YY_BREAK
-case 10:
+case 9:
YY_RULE_SETUP
-#line 143 "dtc-lexer.l"
+#line 144 "dtc-lexer.l"
{ /* label reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
return DT_REF;
}
YY_BREAK
-case 11:
+case 10:
YY_RULE_SETUP
-#line 151 "dtc-lexer.l"
+#line 152 "dtc-lexer.l"
{ /* new-style path reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yytext[yyleng-1] = '\0';
DPRINT("Ref: %s\n", yytext+2);
@@ -1014,44 +1018,44 @@ YY_RULE_SETUP
return DT_REF;
}
YY_BREAK
-case 12:
+case 11:
YY_RULE_SETUP
-#line 160 "dtc-lexer.l"
+#line 161 "dtc-lexer.l"
{ /* old-style path reference */
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Ref: %s\n", yytext+1);
yylval.labelref = strdup(yytext+1);
return DT_REF;
}
YY_BREAK
-case 13:
+case 12:
YY_RULE_SETUP
-#line 168 "dtc-lexer.l"
+#line 169 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
yylval.byte = strtol(yytext, NULL, 16);
DPRINT("Byte: %02x\n", (int)yylval.byte);
return DT_BYTE;
}
YY_BREAK
-case 14:
+case 13:
YY_RULE_SETUP
-#line 176 "dtc-lexer.l"
+#line 177 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("/BYTESTRING\n");
BEGIN_DEFAULT();
return ']';
}
YY_BREAK
-case 15:
+case 14:
YY_RULE_SETUP
-#line 184 "dtc-lexer.l"
+#line 185 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("PropNodeName: %s\n", yytext);
yylval.propnodename = strdup(yytext);
@@ -1059,34 +1063,39 @@ YY_RULE_SETUP
return DT_PROPNODENAME;
}
YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 194 "dtc-lexer.l"
+{
+ yylloc.file = srcpos_file;
+ yylloc.first_line = yylineno;
+ DPRINT("Binary Include\n");
+ return DT_INCBIN;
+ }
+ YY_BREAK
case 16:
/* rule 16 can match eol */
YY_RULE_SETUP
-#line 194 "dtc-lexer.l"
+#line 201 "dtc-lexer.l"
/* eat whitespace */
YY_BREAK
case 17:
/* rule 17 can match eol */
YY_RULE_SETUP
-#line 196 "dtc-lexer.l"
-{
- yylloc.filenum = srcpos_filenum;
- yylloc.first_line = yylineno;
- DPRINT("Comment: %s\n", yytext);
- /* eat comments */
- }
+#line 202 "dtc-lexer.l"
+/* eat C-style comments */
YY_BREAK
case 18:
/* rule 18 can match eol */
YY_RULE_SETUP
#line 203 "dtc-lexer.l"
-/* eat line comments */
+/* eat C++-style comments */
YY_BREAK
case 19:
YY_RULE_SETUP
#line 205 "dtc-lexer.l"
{
- yylloc.filenum = srcpos_filenum;
+ yylloc.file = srcpos_file;
yylloc.first_line = yylineno;
DPRINT("Char: %c (\\x%02x)\n", yytext[0],
(unsigned)yytext[0]);
@@ -1107,7 +1116,7 @@ YY_RULE_SETUP
#line 222 "dtc-lexer.l"
ECHO;
YY_BREAK
-#line 1111 "dtc-lexer.lex.c"
+#line 1120 "dtc-lexer.lex.c"
case YY_END_OF_BUFFER:
{
@@ -1360,6 +1369,14 @@ static int yy_get_next_buffer (void)
else
ret_val = EOB_ACT_CONTINUE_SCAN;
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
(yy_n_chars) += number_to_move;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
@@ -1389,7 +1406,7 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 94 )
+ if ( yy_current_state >= 104 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
@@ -1417,11 +1434,11 @@ static int yy_get_next_buffer (void)
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
{
yy_current_state = (int) yy_def[yy_current_state];
- if ( yy_current_state >= 94 )
+ if ( yy_current_state >= 104 )
yy_c = yy_meta[(unsigned int) yy_c];
}
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
- yy_is_jam = (yy_current_state == 93);
+ yy_is_jam = (yy_current_state == 103);
return yy_is_jam ? 0 : yy_current_state;
}
@@ -1743,7 +1760,9 @@ static void yyensure_buffer_stack (void)
(yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
);
-
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
(yy_buffer_stack_max) = num_to_alloc;
@@ -1761,6 +1780,8 @@ static void yyensure_buffer_stack (void)
((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*)
);
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
/* zero only the new slots.*/
memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
@@ -2072,14 +2093,13 @@ void yyfree (void * ptr )
*/
struct incl_file {
- int filenum;
- FILE *file;
+ struct dtc_file *file;
YY_BUFFER_STATE yy_prev_buf;
int yy_prev_lineno;
struct incl_file *prev;
};
-struct incl_file *incl_file_stack;
+static struct incl_file *incl_file_stack;
/*
@@ -2090,36 +2110,34 @@ struct incl_file *incl_file_stack;
static int incl_depth = 0;
-int push_input_file(const char *filename)
+static void push_input_file(const char *filename)
{
- FILE *f;
struct incl_file *incl_file;
+ struct dtc_file *newfile;
+ struct search_path search, *searchptr = NULL;
- if (!filename) {
- yyerror("No include file name given.");
- return 0;
- }
+ assert(filename);
- if (incl_depth++ >= MAX_INCLUDE_DEPTH) {
- yyerror("Includes nested too deeply");
- return 0;
+ if (incl_depth++ >= MAX_INCLUDE_DEPTH)
+ die("Includes nested too deeply");
+
+ if (srcpos_file) {
+ search.dir = srcpos_file->dir;
+ search.next = NULL;
+ search.prev = NULL;
+ searchptr = &search;
}
- f = dtc_open_file(filename);
+ newfile = dtc_open_file(filename, searchptr);
- incl_file = malloc(sizeof(struct incl_file));
- if (!incl_file) {
- yyerror("Can not allocate include file space.");
- return 0;
- }
+ incl_file = xmalloc(sizeof(struct incl_file));
/*
* Save current context.
*/
incl_file->yy_prev_buf = YY_CURRENT_BUFFER;
incl_file->yy_prev_lineno = yylineno;
- incl_file->filenum = srcpos_filenum;
- incl_file->file = yyin;
+ incl_file->file = srcpos_file;
incl_file->prev = incl_file_stack;
incl_file_stack = incl_file;
@@ -2127,23 +2145,21 @@ int push_input_file(const char *filename)
/*
* Establish new context.
*/
- srcpos_filenum = lookup_file_name(filename, 0);
+ srcpos_file = newfile;
yylineno = 1;
- yyin = f;
+ yyin = newfile->file;
yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
-
- return 1;
}
-int pop_input_file(void)
+static int pop_input_file(void)
{
struct incl_file *incl_file;
if (incl_file_stack == 0)
return 0;
- fclose(yyin);
+ dtc_close_file(srcpos_file);
/*
* Pop.
@@ -2158,17 +2174,14 @@ int pop_input_file(void)
yy_delete_buffer(YY_CURRENT_BUFFER);
yy_switch_to_buffer(incl_file->yy_prev_buf);
yylineno = incl_file->yy_prev_lineno;
- srcpos_filenum = incl_file->filenum;
- yyin = incl_file->file;
+ srcpos_file = incl_file->file;
+ yyin = incl_file->file ? incl_file->file->file : NULL;
/*
* Free old state.
*/
free(incl_file);
- if (YY_CURRENT_BUFFER == 0)
- return 0;
-
return 1;
}
diff --git a/arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped b/arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped
index 28e6ec0296a..27129377e5d 100644
--- a/arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped
+++ b/arch/powerpc/boot/dtc-src/dtc-parser.tab.c_shipped
@@ -75,7 +75,8 @@
DT_BYTE = 264,
DT_STRING = 265,
DT_LABEL = 266,
- DT_REF = 267
+ DT_REF = 267,
+ DT_INCBIN = 268
};
#endif
/* Tokens. */
@@ -89,6 +90,7 @@
#define DT_STRING 265
#define DT_LABEL 266
#define DT_REF 267
+#define DT_INCBIN 268
@@ -96,14 +98,17 @@
/* Copy the first part of user declarations. */
#line 23 "dtc-parser.y"
+#include <stdio.h>
+
#include "dtc.h"
#include "srcpos.h"
-int yylex(void);
-unsigned long long eval_literal(const char *s, int base, int bits);
+extern int yylex(void);
extern struct boot_info *the_boot_info;
+extern int treesource_error;
+static unsigned long long eval_literal(const char *s, int base, int bits);
/* Enabling traces. */
@@ -126,16 +131,16 @@ extern struct boot_info *the_boot_info;
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-#line 34 "dtc-parser.y"
+#line 37 "dtc-parser.y"
{
char *propnodename;
char *literal;
char *labelref;
unsigned int cbase;
- u8 byte;
+ uint8_t byte;
struct data data;
- u64 addr;
+ uint64_t addr;
cell_t cell;
struct property *prop;
struct property *proplist;
@@ -144,7 +149,7 @@ typedef union YYSTYPE
struct reserve_info *re;
}
/* Line 187 of yacc.c. */
-#line 148 "dtc-parser.tab.c"
+#line 153 "dtc-parser.tab.c"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
@@ -169,7 +174,7 @@ typedef struct YYLTYPE
/* Line 216 of yacc.c. */
-#line 173 "dtc-parser.tab.c"
+#line 178 "dtc-parser.tab.c"
#ifdef short
# undef short
@@ -386,20 +391,20 @@ union yyalloc
/* YYFINAL -- State number of the termination state. */
#define YYFINAL 9
/* YYLAST -- Last index in YYTABLE. */
-#define YYLAST 60
+#define YYLAST 73
/* YYNTOKENS -- Number of terminals. */
-#define YYNTOKENS 24
+#define YYNTOKENS 27
/* YYNNTS -- Number of nonterminals. */
#define YYNNTS 20
/* YYNRULES -- Number of rules. */
-#define YYNRULES 43
+#define YYNRULES 45
/* YYNRULES -- Number of states. */
-#define YYNSTATES 67
+#define YYNSTATES 76
/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
#define YYUNDEFTOK 2
-#define YYMAXUTOK 267
+#define YYMAXUTOK 268
#define YYTRANSLATE(YYX) \
((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
@@ -411,15 +416,15 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 23, 14, 2, 15, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 13,
- 19, 18, 20, 2, 2, 2, 2, 2, 2, 2,
+ 24, 26, 2, 2, 25, 15, 2, 16, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 14,
+ 20, 19, 21, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 21, 2, 22, 2, 2, 2, 2, 2, 2,
+ 2, 22, 2, 23, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 16, 2, 17, 2, 2, 2, 2,
+ 2, 2, 2, 17, 2, 18, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
@@ -433,7 +438,7 @@ static const yytype_uint8 yytranslate[] =
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
- 5, 6, 7, 8, 9, 10, 11, 12
+ 5, 6, 7, 8, 9, 10, 11, 12, 13
};
#if YYDEBUG
@@ -443,37 +448,39 @@ static const yytype_uint8 yyprhs[] =
{
0, 0, 3, 8, 11, 12, 15, 21, 22, 25,
27, 34, 36, 38, 41, 47, 48, 51, 57, 61,
- 64, 69, 74, 77, 80, 81, 84, 87, 88, 91,
- 94, 97, 98, 100, 102, 105, 106, 109, 112, 113,
- 116, 119, 123, 124
+ 64, 69, 74, 77, 87, 93, 96, 97, 100, 103,
+ 104, 107, 110, 113, 114, 116, 118, 121, 122, 125,
+ 128, 129, 132, 135, 139, 140
};
/* YYRHS -- A `-1'-separated list of the rules' RHS. */
static const yytype_int8 yyrhs[] =
{
- 25, 0, -1, 3, 13, 26, 31, -1, 28, 31,
- -1, -1, 27, 26, -1, 43, 4, 30, 30, 13,
- -1, -1, 29, 28, -1, 27, -1, 43, 4, 30,
- 14, 30, 13, -1, 6, -1, 7, -1, 15, 32,
- -1, 16, 33, 41, 17, 13, -1, -1, 33, 34,
- -1, 43, 5, 18, 35, 13, -1, 43, 5, 13,
- -1, 36, 10, -1, 36, 19, 37, 20, -1, 36,
- 21, 40, 22, -1, 36, 12, -1, 35, 11, -1,
- -1, 35, 23, -1, 36, 11, -1, -1, 37, 39,
- -1, 37, 12, -1, 37, 11, -1, -1, 8, -1,
- 6, -1, 38, 7, -1, -1, 40, 9, -1, 40,
- 11, -1, -1, 42, 41, -1, 42, 34, -1, 43,
- 5, 32, -1, -1, 11, -1
+ 28, 0, -1, 3, 14, 29, 34, -1, 31, 34,
+ -1, -1, 30, 29, -1, 46, 4, 33, 33, 14,
+ -1, -1, 32, 31, -1, 30, -1, 46, 4, 33,
+ 15, 33, 14, -1, 6, -1, 7, -1, 16, 35,
+ -1, 17, 36, 44, 18, 14, -1, -1, 36, 37,
+ -1, 46, 5, 19, 38, 14, -1, 46, 5, 14,
+ -1, 39, 10, -1, 39, 20, 40, 21, -1, 39,
+ 22, 43, 23, -1, 39, 12, -1, 39, 13, 24,
+ 10, 25, 33, 25, 33, 26, -1, 39, 13, 24,
+ 10, 26, -1, 38, 11, -1, -1, 38, 25, -1,
+ 39, 11, -1, -1, 40, 42, -1, 40, 12, -1,
+ 40, 11, -1, -1, 8, -1, 6, -1, 41, 7,
+ -1, -1, 43, 9, -1, 43, 11, -1, -1, 45,
+ 44, -1, 45, 37, -1, 46, 5, 35, -1, -1,
+ 11, -1
};
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint16 yyrline[] =
{
- 0, 85, 85, 89, 97, 100, 107, 115, 118, 125,
- 129, 136, 140, 147, 154, 162, 165, 172, 176, 183,
- 187, 191, 195, 199, 207, 210, 214, 222, 225, 229,
- 234, 242, 245, 249, 253, 261, 264, 268, 276, 279,
- 283, 291, 299, 302
+ 0, 89, 89, 93, 101, 104, 111, 119, 122, 129,
+ 133, 140, 144, 151, 158, 166, 169, 176, 180, 187,
+ 191, 195, 199, 203, 220, 231, 239, 242, 246, 254,
+ 257, 261, 266, 274, 277, 281, 285, 293, 296, 300,
+ 308, 311, 315, 323, 331, 334
};
#endif
@@ -484,12 +491,12 @@ static const char *const yytname[] =
{
"$end", "error", "$undefined", "DT_V1", "DT_MEMRESERVE",
"DT_PROPNODENAME", "DT_LITERAL", "DT_LEGACYLITERAL", "DT_BASE",
- "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "';'", "'-'", "'/'", "'{'",
- "'}'", "'='", "'<'", "'>'", "'['", "']'", "','", "$accept", "sourcefile",
- "memreserves", "memreserve", "v0_memreserves", "v0_memreserve", "addr",
- "devicetree", "nodedef", "proplist", "propdef", "propdata",
- "propdataprefix", "celllist", "cellbase", "cellval", "bytestring",
- "subnodes", "subnode", "label", 0
+ "DT_BYTE", "DT_STRING", "DT_LABEL", "DT_REF", "DT_INCBIN", "';'", "'-'",
+ "'/'", "'{'", "'}'", "'='", "'<'", "'>'", "'['", "']'", "'('", "','",
+ "')'", "$accept", "sourcefile", "memreserves", "memreserve",
+ "v0_memreserves", "v0_memreserve", "addr", "devicetree", "nodedef",
+ "proplist", "propdef", "propdata", "propdataprefix", "celllist",
+ "cellbase", "cellval", "bytestring", "subnodes", "subnode", "label", 0
};
#endif
@@ -499,19 +506,19 @@ static const char *const yytname[] =
static const yytype_uint16 yytoknum[] =
{
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
- 265, 266, 267, 59, 45, 47, 123, 125, 61, 60,
- 62, 91, 93, 44
+ 265, 266, 267, 268, 59, 45, 47, 123, 125, 61,
+ 60, 62, 91, 93, 40, 44, 41
};
# endif
/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
static const yytype_uint8 yyr1[] =
{
- 0, 24, 25, 25, 26, 26, 27, 28, 28, 29,
- 29, 30, 30, 31, 32, 33, 33, 34, 34, 35,
- 35, 35, 35, 35, 36, 36, 36, 37, 37, 37,
- 37, 38, 38, 39, 39, 40, 40, 40, 41, 41,
- 41, 42, 43, 43
+ 0, 27, 28, 28, 29, 29, 30, 31, 31, 32,
+ 32, 33, 33, 34, 35, 36, 36, 37, 37, 38,
+ 38, 38, 38, 38, 38, 38, 39, 39, 39, 40,
+ 40, 40, 40, 41, 41, 42, 42, 43, 43, 43,
+ 44, 44, 44, 45, 46, 46
};
/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
@@ -519,9 +526,9 @@ static const yytype_uint8 yyr2[] =
{
0, 2, 4, 2, 0, 2, 5, 0, 2, 1,
6, 1, 1, 2, 5, 0, 2, 5, 3, 2,
- 4, 4, 2, 2, 0, 2, 2, 0, 2, 2,
- 2, 0, 1, 1, 2, 0, 2, 2, 0, 2,
- 2, 3, 0, 1
+ 4, 4, 2, 9, 5, 2, 0, 2, 2, 0,
+ 2, 2, 2, 0, 1, 1, 2, 0, 2, 2,
+ 0, 2, 2, 3, 0, 1
};
/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
@@ -529,81 +536,86 @@ static const yytype_uint8 yyr2[] =
means the default is an error. */
static const yytype_uint8 yydefact[] =
{
- 7, 0, 43, 0, 9, 0, 7, 0, 4, 1,
+ 7, 0, 45, 0, 9, 0, 7, 0, 4, 1,
0, 3, 8, 0, 0, 4, 0, 15, 13, 11,
- 12, 0, 2, 5, 0, 38, 0, 0, 0, 16,
- 0, 38, 0, 0, 6, 0, 40, 39, 0, 10,
- 14, 18, 24, 41, 0, 0, 23, 17, 25, 19,
- 26, 22, 27, 35, 31, 0, 33, 32, 30, 29,
- 20, 0, 28, 36, 37, 21, 34
+ 12, 0, 2, 5, 0, 40, 0, 0, 0, 16,
+ 0, 40, 0, 0, 6, 0, 42, 41, 0, 10,
+ 14, 18, 26, 43, 0, 0, 25, 17, 27, 19,
+ 28, 22, 0, 29, 37, 0, 33, 0, 0, 35,
+ 34, 32, 31, 20, 0, 30, 38, 39, 21, 0,
+ 24, 36, 0, 0, 0, 23
};
/* YYDEFGOTO[NTERM-NUM]. */
static const yytype_int8 yydefgoto[] =
{
-1, 3, 14, 4, 5, 6, 27, 11, 18, 25,
- 29, 44, 45, 54, 61, 62, 55, 30, 31, 7
+ 29, 44, 45, 56, 64, 65, 57, 30, 31, 7
};
/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
STATE-NUM. */
-#define YYPACT_NINF -13
+#define YYPACT_NINF -14
static const yytype_int8 yypact[] =
{
- 23, 11, -13, 37, -13, -4, 18, 39, 18, -13,
- 28, -13, -13, 34, -4, 18, 41, -13, -13, -13,
- -13, 25, -13, -13, 34, -3, 34, 33, 34, -13,
- 30, -3, 43, 36, -13, 38, -13, -13, 20, -13,
- -13, -13, -13, -13, 2, 9, -13, -13, -13, -13,
- -13, -13, -13, -13, -2, -6, -13, -13, -13, -13,
- -13, 45, -13, -13, -13, -13, -13
+ 30, -11, -14, 7, -14, -1, 27, 13, 27, -14,
+ 8, -14, -14, 40, -1, 27, 35, -14, -14, -14,
+ -14, 21, -14, -14, 40, 24, 40, 28, 40, -14,
+ 32, 24, 46, 38, -14, 39, -14, -14, 26, -14,
+ -14, -14, -14, -14, -9, 10, -14, -14, -14, -14,
+ -14, -14, 31, -14, -14, 44, -2, 3, 23, -14,
+ -14, -14, -14, -14, 50, -14, -14, -14, -14, 40,
+ -14, -14, 33, 40, 36, -14
};
/* YYPGOTO[NTERM-NUM]. */
static const yytype_int8 yypgoto[] =
{
- -13, -13, 35, 27, 47, -13, -12, 40, 17, -13,
- 26, -13, -13, -13, -13, -13, -13, 29, -13, -8
+ -14, -14, 48, 29, 53, -14, -13, 47, 34, -14,
+ 37, -14, -14, -14, -14, -14, -14, 42, -14, -7
};
/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
positive, shift that token. If negative, reduce the rule which
number is the opposite. If zero, do what YYDEFACT says.
If YYTABLE_NINF, syntax error. */
-#define YYTABLE_NINF -43
+#define YYTABLE_NINF -45
static const yytype_int8 yytable[] =
{
- 16, 21, -42, 63, 56, 64, 57, 16, 2, 58,
- 59, 10, 28, 46, 33, 47, 65, 32, 60, 49,
- 50, 51, -42, 32, 8, 48, 1, -42, 52, 2,
- 53, 19, 20, 41, 2, 15, 17, 9, 42, 26,
- 19, 20, 15, 13, 17, 24, 34, 35, 38, 39,
- 23, 40, 66, 12, 22, 43, 0, 36, 0, 0,
- 37
+ 21, 16, 46, 8, 59, 47, 60, 9, 16, 61,
+ 62, 28, 66, 33, 67, 10, 48, 13, 32, 63,
+ 49, 50, 51, 52, 32, 17, 68, 19, 20, -44,
+ 53, -44, 54, 1, -44, 2, 26, 15, 2, 24,
+ 41, 2, 34, 17, 15, 42, 19, 20, 69, 70,
+ 35, 38, 39, 40, 58, 55, 72, 71, 73, 12,
+ 74, 22, 75, 23, 0, 0, 0, 0, 36, 0,
+ 0, 0, 43, 37
};
static const yytype_int8 yycheck[] =
{
- 8, 13, 5, 9, 6, 11, 8, 15, 11, 11,
- 12, 15, 24, 11, 26, 13, 22, 25, 20, 10,
- 11, 12, 4, 31, 13, 23, 3, 4, 19, 11,
- 21, 6, 7, 13, 11, 8, 16, 0, 18, 14,
- 6, 7, 15, 4, 16, 4, 13, 17, 5, 13,
- 15, 13, 7, 6, 14, 38, -1, 31, -1, -1,
- 31
+ 13, 8, 11, 14, 6, 14, 8, 0, 15, 11,
+ 12, 24, 9, 26, 11, 16, 25, 4, 25, 21,
+ 10, 11, 12, 13, 31, 17, 23, 6, 7, 5,
+ 20, 4, 22, 3, 4, 11, 15, 8, 11, 4,
+ 14, 11, 14, 17, 15, 19, 6, 7, 25, 26,
+ 18, 5, 14, 14, 10, 24, 69, 7, 25, 6,
+ 73, 14, 26, 15, -1, -1, -1, -1, 31, -1,
+ -1, -1, 38, 31
};
/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
symbol of state STATE-NUM. */
static const yytype_uint8 yystos[] =
{
- 0, 3, 11, 25, 27, 28, 29, 43, 13, 0,
- 15, 31, 28, 4, 26, 27, 43, 16, 32, 6,
- 7, 30, 31, 26, 4, 33, 14, 30, 30, 34,
- 41, 42, 43, 30, 13, 17, 34, 41, 5, 13,
- 13, 13, 18, 32, 35, 36, 11, 13, 23, 10,
- 11, 12, 19, 21, 37, 40, 6, 8, 11, 12,
- 20, 38, 39, 9, 11, 22, 7
+ 0, 3, 11, 28, 30, 31, 32, 46, 14, 0,
+ 16, 34, 31, 4, 29, 30, 46, 17, 35, 6,
+ 7, 33, 34, 29, 4, 36, 15, 33, 33, 37,
+ 44, 45, 46, 33, 14, 18, 37, 44, 5, 14,
+ 14, 14, 19, 35, 38, 39, 11, 14, 25, 10,
+ 11, 12, 13, 20, 22, 24, 40, 43, 10, 6,
+ 8, 11, 12, 21, 41, 42, 9, 11, 23, 25,
+ 26, 7, 33, 25, 33, 26
};
#define yyerrok (yyerrstatus = 0)
@@ -1440,289 +1452,323 @@ yyreduce:
switch (yyn)
{
case 2:
-#line 86 "dtc-parser.y"
+#line 90 "dtc-parser.y"
{
- the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node));
+ the_boot_info = build_boot_info((yyvsp[(3) - (4)].re), (yyvsp[(4) - (4)].node), 0);
;}
break;
case 3:
-#line 90 "dtc-parser.y"
+#line 94 "dtc-parser.y"
{
- the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node));
+ the_boot_info = build_boot_info((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].node), 0);
;}
break;
case 4:
-#line 97 "dtc-parser.y"
+#line 101 "dtc-parser.y"
{
(yyval.re) = NULL;
;}
break;
case 5:
-#line 101 "dtc-parser.y"
+#line 105 "dtc-parser.y"
{
(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
;}
break;
case 6:
-#line 108 "dtc-parser.y"
+#line 112 "dtc-parser.y"
{
(yyval.re) = build_reserve_entry((yyvsp[(3) - (5)].addr), (yyvsp[(4) - (5)].addr), (yyvsp[(1) - (5)].labelref));
;}
break;
case 7:
-#line 115 "dtc-parser.y"
+#line 119 "dtc-parser.y"
{
(yyval.re) = NULL;
;}
break;
case 8:
-#line 119 "dtc-parser.y"
+#line 123 "dtc-parser.y"
{
(yyval.re) = chain_reserve_entry((yyvsp[(1) - (2)].re), (yyvsp[(2) - (2)].re));
;}
break;
case 9:
-#line 126 "dtc-parser.y"
+#line 130 "dtc-parser.y"
{
(yyval.re) = (yyvsp[(1) - (1)].re);
;}
break;
case 10:
-#line 130 "dtc-parser.y"
+#line 134 "dtc-parser.y"
{
(yyval.re) = build_reserve_entry((yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr) - (yyvsp[(3) - (6)].addr) + 1, (yyvsp[(1) - (6)].labelref));
;}
break;
case 11:
-#line 137 "dtc-parser.y"
+#line 141 "dtc-parser.y"
{
(yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 0, 64);
;}
break;
case 12:
-#line 141 "dtc-parser.y"
+#line 145 "dtc-parser.y"
{
(yyval.addr) = eval_literal((yyvsp[(1) - (1)].literal), 16, 64);
;}
break;
case 13:
-#line 148 "dtc-parser.y"
+#line 152 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(2) - (2)].node), "", NULL);
;}
break;
case 14:
-#line 155 "dtc-parser.y"
+#line 159 "dtc-parser.y"
{
(yyval.node) = build_node((yyvsp[(2) - (5)].proplist), (yyvsp[(3) - (5)].nodelist));
;}
break;
case 15:
-#line 162 "dtc-parser.y"
+#line 166 "dtc-parser.y"
{
(yyval.proplist) = NULL;
;}
break;
case 16:
-#line 166 "dtc-parser.y"
+#line 170 "dtc-parser.y"
{
(yyval.proplist) = chain_property((yyvsp[(2) - (2)].prop), (yyvsp[(1) - (2)].proplist));
;}
break;
case 17:
-#line 173 "dtc-parser.y"
+#line 177 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(2) - (5)].propnodename), (yyvsp[(4) - (5)].data), (yyvsp[(1) - (5)].labelref));
;}
break;
case 18:
-#line 177 "dtc-parser.y"
+#line 181 "dtc-parser.y"
{
(yyval.prop) = build_property((yyvsp[(2) - (3)].propnodename), empty_data, (yyvsp[(1) - (3)].labelref));
;}
break;
case 19:
-#line 184 "dtc-parser.y"
+#line 188 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].data));
;}
break;
case 20:
-#line 188 "dtc-parser.y"
+#line 192 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
;}
break;
case 21:
-#line 192 "dtc-parser.y"
+#line 196 "dtc-parser.y"
{
(yyval.data) = data_merge((yyvsp[(1) - (4)].data), (yyvsp[(3) - (4)].data));
;}
break;
case 22:
-#line 196 "dtc-parser.y"
+#line 200 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), REF_PATH, (yyvsp[(2) - (2)].labelref));
;}
break;
case 23:
-#line 200 "dtc-parser.y"
+#line 204 "dtc-parser.y"
{
- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file((yyvsp[(4) - (9)].data).val, &path);
+ struct data d = empty_data;
+
+ if ((yyvsp[(6) - (9)].addr) != 0)
+ if (fseek(file->file, (yyvsp[(6) - (9)].addr), SEEK_SET) != 0)
+ yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)(yyvsp[(6) - (9)].addr),
+ (yyvsp[(4) - (9)].data).val, strerror(errno));
+
+ d = data_copy_file(file->file, (yyvsp[(8) - (9)].addr));
+
+ (yyval.data) = data_merge((yyvsp[(1) - (9)].data), d);
+ dtc_close_file(file);
;}
break;
case 24:
-#line 207 "dtc-parser.y"
+#line 221 "dtc-parser.y"
{
- (yyval.data) = empty_data;
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file((yyvsp[(4) - (5)].data).val, &path);
+ struct data d = empty_data;
+
+ d = data_copy_file(file->file, -1);
+
+ (yyval.data) = data_merge((yyvsp[(1) - (5)].data), d);
+ dtc_close_file(file);
;}
break;
case 25:
-#line 211 "dtc-parser.y"
+#line 232 "dtc-parser.y"
{
- (yyval.data) = (yyvsp[(1) - (2)].data);
+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
;}
break;
case 26:
-#line 215 "dtc-parser.y"
+#line 239 "dtc-parser.y"
{
- (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
+ (yyval.data) = empty_data;
;}
break;
case 27:
-#line 222 "dtc-parser.y"
+#line 243 "dtc-parser.y"
{
- (yyval.data) = empty_data;
+ (yyval.data) = (yyvsp[(1) - (2)].data);
;}
break;
case 28:
-#line 226 "dtc-parser.y"
+#line 247 "dtc-parser.y"
{
- (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell));
+ (yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
;}
break;
case 29:
-#line 230 "dtc-parser.y"
+#line 254 "dtc-parser.y"
+ {
+ (yyval.data) = empty_data;
+ ;}
+ break;
+
+ case 30:
+#line 258 "dtc-parser.y"
+ {
+ (yyval.data) = data_append_cell((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].cell));
+ ;}
+ break;
+
+ case 31:
+#line 262 "dtc-parser.y"
{
(yyval.data) = data_append_cell(data_add_marker((yyvsp[(1) - (2)].data), REF_PHANDLE,
(yyvsp[(2) - (2)].labelref)), -1);
;}
break;
- case 30:
-#line 235 "dtc-parser.y"
+ case 32:
+#line 267 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
;}
break;
- case 31:
-#line 242 "dtc-parser.y"
+ case 33:
+#line 274 "dtc-parser.y"
{
(yyval.cbase) = 16;
;}
break;
- case 33:
-#line 250 "dtc-parser.y"
+ case 35:
+#line 282 "dtc-parser.y"
{
(yyval.cell) = eval_literal((yyvsp[(1) - (1)].literal), 0, 32);
;}
break;
- case 34:
-#line 254 "dtc-parser.y"
+ case 36:
+#line 286 "dtc-parser.y"
{
(yyval.cell) = eval_literal((yyvsp[(2) - (2)].literal), (yyvsp[(1) - (2)].cbase), 32);
;}
break;
- case 35:
-#line 261 "dtc-parser.y"
+ case 37:
+#line 293 "dtc-parser.y"
{
(yyval.data) = empty_data;
;}
break;
- case 36:
-#line 265 "dtc-parser.y"
+ case 38:
+#line 297 "dtc-parser.y"
{
(yyval.data) = data_append_byte((yyvsp[(1) - (2)].data), (yyvsp[(2) - (2)].byte));
;}
break;
- case 37:
-#line 269 "dtc-parser.y"
+ case 39:
+#line 301 "dtc-parser.y"
{
(yyval.data) = data_add_marker((yyvsp[(1) - (2)].data), LABEL, (yyvsp[(2) - (2)].labelref));
;}
break;
- case 38:
-#line 276 "dtc-parser.y"
+ case 40:
+#line 308 "dtc-parser.y"
{
(yyval.nodelist) = NULL;
;}
break;
- case 39:
-#line 280 "dtc-parser.y"
+ case 41:
+#line 312 "dtc-parser.y"
{
(yyval.nodelist) = chain_node((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].nodelist));
;}
break;
- case 40:
-#line 284 "dtc-parser.y"
+ case 42:
+#line 316 "dtc-parser.y"
{
- yyerror("syntax error: properties must precede subnodes\n");
+ yyerror("syntax error: properties must precede subnodes");
YYERROR;
;}
break;
- case 41:
-#line 292 "dtc-parser.y"
+ case 43:
+#line 324 "dtc-parser.y"
{
(yyval.node) = name_node((yyvsp[(3) - (3)].node), (yyvsp[(2) - (3)].propnodename), (yyvsp[(1) - (3)].labelref));
;}
break;
- case 42:
-#line 299 "dtc-parser.y"
+ case 44:
+#line 331 "dtc-parser.y"
{
(yyval.labelref) = NULL;
;}
break;
- case 43:
-#line 303 "dtc-parser.y"
+ case 45:
+#line 335 "dtc-parser.y"
{
(yyval.labelref) = (yyvsp[(1) - (1)].labelref);
;}
@@ -1730,7 +1776,7 @@ yyreduce:
/* Line 1267 of yacc.c. */
-#line 1734 "dtc-parser.tab.c"
+#line 1780 "dtc-parser.tab.c"
default: break;
}
YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -1950,21 +1996,32 @@ yyreturn:
}
-#line 308 "dtc-parser.y"
+#line 340 "dtc-parser.y"
-void yyerror (char const *s)
+void yyerrorf(char const *s, ...)
{
- const char *fname = srcpos_filename_for_num(yylloc.filenum);
+ const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
+ va_list va;
+ va_start(va, s);
if (strcmp(fname, "-") == 0)
fname = "stdin";
- fprintf(stderr, "%s:%d %s\n",
- fname, yylloc.first_line, s);
+ fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
+ vfprintf(stderr, s, va);
+ fprintf(stderr, "\n");
+
+ treesource_error = 1;
+ va_end(va);
+}
+
+void yyerror (char const *s)
+{
+ yyerrorf("%s", s);
}
-unsigned long long eval_literal(const char *s, int base, int bits)
+static unsigned long long eval_literal(const char *s, int base, int bits)
{
unsigned long long val;
char *e;
diff --git a/arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped b/arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped
index 4707b029ed2..ba99100d55c 100644
--- a/arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped
+++ b/arch/powerpc/boot/dtc-src/dtc-parser.tab.h_shipped
@@ -48,7 +48,8 @@
DT_BYTE = 264,
DT_STRING = 265,
DT_LABEL = 266,
- DT_REF = 267
+ DT_REF = 267,
+ DT_INCBIN = 268
};
#endif
/* Tokens. */
@@ -62,22 +63,23 @@
#define DT_STRING 265
#define DT_LABEL 266
#define DT_REF 267
+#define DT_INCBIN 268
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
-#line 34 "dtc-parser.y"
+#line 37 "dtc-parser.y"
{
char *propnodename;
char *literal;
char *labelref;
unsigned int cbase;
- u8 byte;
+ uint8_t byte;
struct data data;
- u64 addr;
+ uint64_t addr;
cell_t cell;
struct property *prop;
struct property *proplist;
@@ -86,7 +88,7 @@ typedef union YYSTYPE
struct reserve_info *re;
}
/* Line 1489 of yacc.c. */
-#line 90 "dtc-parser.tab.h"
+#line 92 "dtc-parser.tab.h"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
diff --git a/arch/powerpc/boot/dtc-src/dtc-parser.y b/arch/powerpc/boot/dtc-src/dtc-parser.y
index 002ea7fef18..b2ab562420e 100644
--- a/arch/powerpc/boot/dtc-src/dtc-parser.y
+++ b/arch/powerpc/boot/dtc-src/dtc-parser.y
@@ -21,14 +21,17 @@
%locations
%{
+#include <stdio.h>
+
#include "dtc.h"
#include "srcpos.h"
-int yylex(void);
-unsigned long long eval_literal(const char *s, int base, int bits);
+extern int yylex(void);
extern struct boot_info *the_boot_info;
+extern int treesource_error;
+static unsigned long long eval_literal(const char *s, int base, int bits);
%}
%union {
@@ -36,10 +39,10 @@ extern struct boot_info *the_boot_info;
char *literal;
char *labelref;
unsigned int cbase;
- u8 byte;
+ uint8_t byte;
struct data data;
- u64 addr;
+ uint64_t addr;
cell_t cell;
struct property *prop;
struct property *proplist;
@@ -58,6 +61,7 @@ extern struct boot_info *the_boot_info;
%token <data> DT_STRING
%token <labelref> DT_LABEL
%token <labelref> DT_REF
+%token DT_INCBIN
%type <data> propdata
%type <data> propdataprefix
@@ -84,11 +88,11 @@ extern struct boot_info *the_boot_info;
sourcefile:
DT_V1 ';' memreserves devicetree
{
- the_boot_info = build_boot_info($3, $4);
+ the_boot_info = build_boot_info($3, $4, 0);
}
| v0_memreserves devicetree
{
- the_boot_info = build_boot_info($1, $2);
+ the_boot_info = build_boot_info($1, $2, 0);
}
;
@@ -196,6 +200,34 @@ propdata:
{
$$ = data_add_marker($1, REF_PATH, $2);
}
+ | propdataprefix DT_INCBIN '(' DT_STRING ',' addr ',' addr ')'
+ {
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file($4.val, &path);
+ struct data d = empty_data;
+
+ if ($6 != 0)
+ if (fseek(file->file, $6, SEEK_SET) != 0)
+ yyerrorf("Couldn't seek to offset %llu in \"%s\": %s",
+ (unsigned long long)$6,
+ $4.val, strerror(errno));
+
+ d = data_copy_file(file->file, $8);
+
+ $$ = data_merge($1, d);
+ dtc_close_file(file);
+ }
+ | propdataprefix DT_INCBIN '(' DT_STRING ')'
+ {
+ struct search_path path = { srcpos_file->dir, NULL, NULL };
+ struct dtc_file *file = dtc_open_file($4.val, &path);
+ struct data d = empty_data;
+
+ d = data_copy_file(file->file, -1);
+
+ $$ = data_merge($1, d);
+ dtc_close_file(file);
+ }
| propdata DT_LABEL
{
$$ = data_add_marker($1, LABEL, $2);
@@ -282,7 +314,7 @@ subnodes:
}
| subnode propdef
{
- yyerror("syntax error: properties must precede subnodes\n");
+ yyerror("syntax error: properties must precede subnodes");
YYERROR;
}
;
@@ -307,18 +339,29 @@ label:
%%
-void yyerror (char const *s)
+void yyerrorf(char const *s, ...)
{
- const char *fname = srcpos_filename_for_num(yylloc.filenum);
+ const char *fname = srcpos_file ? srcpos_file->name : "<no-file>";
+ va_list va;
+ va_start(va, s);
if (strcmp(fname, "-") == 0)
fname = "stdin";
- fprintf(stderr, "%s:%d %s\n",
- fname, yylloc.first_line, s);
+ fprintf(stderr, "%s:%d ", fname, yylloc.first_line);
+ vfprintf(stderr, s, va);
+ fprintf(stderr, "\n");
+
+ treesource_error = 1;
+ va_end(va);
+}
+
+void yyerror (char const *s)
+{
+ yyerrorf("%s", s);
}
-unsigned long long eval_literal(const char *s, int base, int bits)
+static unsigned long long eval_literal(const char *s, int base, int bits)
{
unsigned long long val;
char *e;
diff --git a/arch/powerpc/boot/dtc-src/dtc.c b/arch/powerpc/boot/dtc-src/dtc.c
index 01131d7c2d5..d8fd43b4ac1 100644
--- a/arch/powerpc/boot/dtc-src/dtc.c
+++ b/arch/powerpc/boot/dtc-src/dtc.c
@@ -55,7 +55,7 @@ char *join_path(const char *path, const char *name)
return str;
}
-void fill_fullpaths(struct node *tree, const char *prefix)
+static void fill_fullpaths(struct node *tree, const char *prefix)
{
struct node *child;
const char *unit;
@@ -106,7 +106,7 @@ static void __attribute__ ((noreturn)) usage(void)
fprintf(stderr, "\t\tForce - try to produce output even if the input tree has errors\n");
fprintf(stderr, "\t-v\n");
fprintf(stderr, "\t\tPrint DTC version and exit\n");
- exit(2);
+ exit(3);
}
int main(int argc, char *argv[])
@@ -118,10 +118,9 @@ int main(int argc, char *argv[])
int force = 0, check = 0;
const char *arg;
int opt;
- FILE *inf = NULL;
FILE *outf = NULL;
int outversion = DEFAULT_FDT_VERSION;
- int boot_cpuid_phys = 0xfeedbeef;
+ long long cmdline_boot_cpuid = -1;
quiet = 0;
reservenum = 0;
@@ -161,11 +160,11 @@ int main(int argc, char *argv[])
quiet++;
break;
case 'b':
- boot_cpuid_phys = strtol(optarg, NULL, 0);
+ cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
break;
case 'v':
- printf("Version: %s\n", DTC_VERSION);
- exit(0);
+ printf("Version: %s\n", DTC_VERSION);
+ exit(0);
case 'h':
default:
usage();
@@ -180,31 +179,27 @@ int main(int argc, char *argv[])
arg = argv[optind];
/* minsize and padsize are mutually exclusive */
- if ((minsize) && (padsize)) {
+ if (minsize && padsize)
die("Can't set both -p and -S\n");
- }
fprintf(stderr, "DTC: %s->%s on file \"%s\"\n",
inform, outform, arg);
- if (streq(inform, "dts")) {
+ if (streq(inform, "dts"))
bi = dt_from_source(arg);
- } else if (streq(inform, "fs")) {
+ else if (streq(inform, "fs"))
bi = dt_from_fs(arg);
- } else if(streq(inform, "dtb")) {
- inf = dtc_open_file(arg);
- bi = dt_from_blob(inf);
- } else {
+ else if(streq(inform, "dtb"))
+ bi = dt_from_blob(arg);
+ else
die("Unknown input format \"%s\"\n", inform);
- }
- if (inf && (inf != stdin))
- fclose(inf);
+ if (cmdline_boot_cpuid != -1)
+ bi->boot_cpuid_phys = cmdline_boot_cpuid;
- if (! bi || ! bi->dt)
- die("Couldn't read input tree\n");
+ fill_fullpaths(bi->dt, "");
+ process_checks(force, bi);
- process_checks(force, bi, check, outversion, boot_cpuid_phys);
if (streq(outname, "-")) {
outf = stdout;
@@ -218,9 +213,9 @@ int main(int argc, char *argv[])
if (streq(outform, "dts")) {
dt_to_source(outf, bi);
} else if (streq(outform, "dtb")) {
- dt_to_blob(outf, bi, outversion, boot_cpuid_phys);
+ dt_to_blob(outf, bi, outversion);
} else if (streq(outform, "asm")) {
- dt_to_asm(outf, bi, outversion, boot_cpuid_phys);
+ dt_to_asm(outf, bi, outversion);
} else if (streq(outform, "null")) {
/* do nothing */
} else {
diff --git a/arch/powerpc/boot/dtc-src/dtc.h b/arch/powerpc/boot/dtc-src/dtc.h
index 65281777a16..08d54c87008 100644
--- a/arch/powerpc/boot/dtc-src/dtc.h
+++ b/arch/powerpc/boot/dtc-src/dtc.h
@@ -30,10 +30,8 @@
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
-#include <netinet/in.h>
-#include <endian.h>
-#include <byteswap.h>
+#include <libfdt_env.h>
#include <fdt.h>
#define DEFAULT_FDT_VERSION 17
@@ -75,25 +73,8 @@ static inline void *xrealloc(void *p, size_t len)
return new;
}
-typedef uint8_t u8;
-typedef uint16_t u16;
-typedef uint32_t u32;
-typedef uint64_t u64;
-typedef u32 cell_t;
+typedef uint32_t cell_t;
-#define cpu_to_be16(x) htons(x)
-#define be16_to_cpu(x) ntohs(x)
-
-#define cpu_to_be32(x) htonl(x)
-#define be32_to_cpu(x) ntohl(x)
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_be64(x) (x)
-#define be64_to_cpu(x) (x)
-#else
-#define cpu_to_be64(x) bswap_64(x)
-#define be64_to_cpu(x) bswap_64(x)
-#endif
#define streq(a, b) (strcmp((a), (b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
@@ -118,7 +99,6 @@ struct marker {
struct data {
int len;
char *val;
- int asize;
struct marker *markers;
};
@@ -145,7 +125,7 @@ struct data data_insert_at_marker(struct data d, struct marker *m,
struct data data_merge(struct data d1, struct data d2);
struct data data_append_cell(struct data d, cell_t word);
struct data data_append_re(struct data d, const struct fdt_reserve_entry *re);
-struct data data_append_addr(struct data d, u64 addr);
+struct data data_append_addr(struct data d, uint64_t addr);
struct data data_append_byte(struct data d, uint8_t byte);
struct data data_append_zeroes(struct data d, int len);
struct data data_append_align(struct data d, int align);
@@ -223,7 +203,7 @@ struct reserve_info {
char *label;
};
-struct reserve_info *build_reserve_entry(u64 start, u64 len, char *label);
+struct reserve_info *build_reserve_entry(uint64_t start, uint64_t len, char *label);
struct reserve_info *chain_reserve_entry(struct reserve_info *first,
struct reserve_info *list);
struct reserve_info *add_reserve_entry(struct reserve_info *list,
@@ -233,24 +213,22 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
struct boot_info {
struct reserve_info *reservelist;
struct node *dt; /* the device tree */
+ uint32_t boot_cpuid_phys;
};
struct boot_info *build_boot_info(struct reserve_info *reservelist,
- struct node *tree);
+ struct node *tree, uint32_t boot_cpuid_phys);
/* Checks */
-void process_checks(int force, struct boot_info *bi,
- int checkflag, int outversion, int boot_cpuid_phys);
+void process_checks(int force, struct boot_info *bi);
/* Flattened trees */
-void dt_to_blob(FILE *f, struct boot_info *bi, int version,
- int boot_cpuid_phys);
-void dt_to_asm(FILE *f, struct boot_info *bi, int version,
- int boot_cpuid_phys);
+void dt_to_blob(FILE *f, struct boot_info *bi, int version);
+void dt_to_asm(FILE *f, struct boot_info *bi, int version);
-struct boot_info *dt_from_blob(FILE *f);
+struct boot_info *dt_from_blob(const char *fname);
/* Tree source */
@@ -264,6 +242,5 @@ struct boot_info *dt_from_fs(const char *dirname);
/* misc */
char *join_path(const char *path, const char *name);
-void fill_fullpaths(struct node *tree, const char *prefix);
#endif /* _DTC_H */
diff --git a/arch/powerpc/boot/dtc-src/flattree.c b/arch/powerpc/boot/dtc-src/flattree.c
index a7cfb843d33..76acd28c068 100644
--- a/arch/powerpc/boot/dtc-src/flattree.c
+++ b/arch/powerpc/boot/dtc-src/flattree.c
@@ -19,6 +19,7 @@
*/
#include "dtc.h"
+#include "srcpos.h"
#define FTF_FULLPATH 0x1
#define FTF_VARALIGN 0x2
@@ -162,28 +163,18 @@ static void asm_emit_data(void *e, struct data d)
{
FILE *f = e;
int off = 0;
- struct marker *m;
+ struct marker *m = d.markers;
- m = d.markers;
- while (m) {
- if (m->type == LABEL)
- emit_offset_label(f, m->ref, m->offset);
- m = m->next;
- }
+ for_each_marker_of_type(m, LABEL)
+ emit_offset_label(f, m->ref, m->offset);
- while ((d.len - off) >= sizeof(u32)) {
+ while ((d.len - off) >= sizeof(uint32_t)) {
fprintf(f, "\t.long\t0x%x\n",
- be32_to_cpu(*((u32 *)(d.val+off))));
- off += sizeof(u32);
- }
-
- if ((d.len - off) >= sizeof(u16)) {
- fprintf(f, "\t.short\t0x%hx\n",
- be16_to_cpu(*((u16 *)(d.val+off))));
- off += sizeof(u16);
+ fdt32_to_cpu(*((uint32_t *)(d.val+off))));
+ off += sizeof(uint32_t);
}
- if ((d.len - off) >= 1) {
+ while ((d.len - off) >= 1) {
fprintf(f, "\t.byte\t0x%hhx\n", d.val[off]);
off += 1;
}
@@ -336,29 +327,28 @@ static void make_fdt_header(struct fdt_header *fdt,
memset(fdt, 0xff, sizeof(*fdt));
- fdt->magic = cpu_to_be32(FDT_MAGIC);
- fdt->version = cpu_to_be32(vi->version);
- fdt->last_comp_version = cpu_to_be32(vi->last_comp_version);
+ fdt->magic = cpu_to_fdt32(FDT_MAGIC);
+ fdt->version = cpu_to_fdt32(vi->version);
+ fdt->last_comp_version = cpu_to_fdt32(vi->last_comp_version);
/* Reserve map should be doubleword aligned */
reserve_off = ALIGN(vi->hdr_size, 8);
- fdt->off_mem_rsvmap = cpu_to_be32(reserve_off);
- fdt->off_dt_struct = cpu_to_be32(reserve_off + reservesize);
- fdt->off_dt_strings = cpu_to_be32(reserve_off + reservesize
+ fdt->off_mem_rsvmap = cpu_to_fdt32(reserve_off);
+ fdt->off_dt_struct = cpu_to_fdt32(reserve_off + reservesize);
+ fdt->off_dt_strings = cpu_to_fdt32(reserve_off + reservesize
+ dtsize);
- fdt->totalsize = cpu_to_be32(reserve_off + reservesize + dtsize + strsize);
+ fdt->totalsize = cpu_to_fdt32(reserve_off + reservesize + dtsize + strsize);
if (vi->flags & FTF_BOOTCPUID)
- fdt->boot_cpuid_phys = cpu_to_be32(boot_cpuid_phys);
+ fdt->boot_cpuid_phys = cpu_to_fdt32(boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE)
- fdt->size_dt_strings = cpu_to_be32(strsize);
+ fdt->size_dt_strings = cpu_to_fdt32(strsize);
if (vi->flags & FTF_STRUCTSIZE)
- fdt->size_dt_struct = cpu_to_be32(dtsize);
+ fdt->size_dt_struct = cpu_to_fdt32(dtsize);
}
-void dt_to_blob(FILE *f, struct boot_info *bi, int version,
- int boot_cpuid_phys)
+void dt_to_blob(FILE *f, struct boot_info *bi, int version)
{
struct version_info *vi = NULL;
int i;
@@ -383,26 +373,26 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
/* Make header */
make_fdt_header(&fdt, vi, reservebuf.len, dtbuf.len, strbuf.len,
- boot_cpuid_phys);
+ bi->boot_cpuid_phys);
/*
* If the user asked for more space than is used, adjust the totalsize.
*/
if (minsize > 0) {
- padlen = minsize - be32_to_cpu(fdt.totalsize);
+ padlen = minsize - fdt32_to_cpu(fdt.totalsize);
if ((padlen < 0) && (quiet < 1))
fprintf(stderr,
"Warning: blob size %d >= minimum size %d\n",
- be32_to_cpu(fdt.totalsize), minsize);
+ fdt32_to_cpu(fdt.totalsize), minsize);
}
if (padsize > 0)
padlen = padsize;
if (padlen > 0) {
- int tsize = be32_to_cpu(fdt.totalsize);
+ int tsize = fdt32_to_cpu(fdt.totalsize);
tsize += padlen;
- fdt.totalsize = cpu_to_be32(tsize);
+ fdt.totalsize = cpu_to_fdt32(tsize);
}
/*
@@ -410,7 +400,7 @@ void dt_to_blob(FILE *f, struct boot_info *bi, int version,
* the reserve buffer, add the reserve map terminating zeroes,
* the device tree itself, and finally the strings.
*/
- blob = data_append_data(blob, &fdt, sizeof(fdt));
+ blob = data_append_data(blob, &fdt, vi->hdr_size);
blob = data_append_align(blob, 8);
blob = data_merge(blob, reservebuf);
blob = data_append_zeroes(blob, sizeof(struct fdt_reserve_entry));
@@ -449,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf)
}
}
-void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
+void dt_to_asm(FILE *f, struct boot_info *bi, int version)
{
struct version_info *vi = NULL;
int i;
@@ -489,7 +479,7 @@ void dt_to_asm(FILE *f, struct boot_info *bi, int version, int boot_cpuid_phys)
if (vi->flags & FTF_BOOTCPUID)
fprintf(f, "\t.long\t%i\t\t\t\t\t/* boot_cpuid_phys */\n",
- boot_cpuid_phys);
+ bi->boot_cpuid_phys);
if (vi->flags & FTF_STRTABSIZE)
fprintf(f, "\t.long\t_%s_strings_end - _%s_strings_start\t/* size_dt_strings */\n",
@@ -579,15 +569,15 @@ static void flat_read_chunk(struct inbuf *inb, void *p, int len)
inb->ptr += len;
}
-static u32 flat_read_word(struct inbuf *inb)
+static uint32_t flat_read_word(struct inbuf *inb)
{
- u32 val;
+ uint32_t val;
assert(((inb->ptr - inb->base) % sizeof(val)) == 0);
flat_read_chunk(inb, &val, sizeof(val));
- return be32_to_cpu(val);
+ return fdt32_to_cpu(val);
}
static void flat_realign(struct inbuf *inb, int align)
@@ -615,7 +605,7 @@ static char *flat_read_string(struct inbuf *inb)
inb->ptr += len;
- flat_realign(inb, sizeof(u32));
+ flat_realign(inb, sizeof(uint32_t));
return str;
}
@@ -632,7 +622,7 @@ static struct data flat_read_data(struct inbuf *inb, int len)
flat_read_chunk(inb, d.val, len);
- flat_realign(inb, sizeof(u32));
+ flat_realign(inb, sizeof(uint32_t));
return d;
}
@@ -659,7 +649,7 @@ static char *flat_read_stringtable(struct inbuf *inb, int offset)
static struct property *flat_read_property(struct inbuf *dtbuf,
struct inbuf *strbuf, int flags)
{
- u32 proplen, stroff;
+ uint32_t proplen, stroff;
char *name;
struct data val;
@@ -693,8 +683,8 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
p = inb->ptr;
while (1) {
flat_read_chunk(inb, &re, sizeof(re));
- re.address = be64_to_cpu(re.address);
- re.size = be64_to_cpu(re.size);
+ re.address = fdt64_to_cpu(re.address);
+ re.size = fdt64_to_cpu(re.size);
if (re.size == 0)
break;
@@ -708,77 +698,37 @@ static struct reserve_info *flat_read_mem_reserve(struct inbuf *inb)
static char *nodename_from_path(const char *ppath, const char *cpath)
{
- const char *lslash;
int plen;
- lslash = strrchr(cpath, '/');
- if (! lslash)
- return NULL;
-
- plen = lslash - cpath;
-
- if (streq(cpath, "/") && streq(ppath, ""))
- return "";
-
- if ((plen == 0) && streq(ppath, "/"))
- return strdup(lslash+1);
-
- if (! strneq(ppath, cpath, plen))
- return NULL;
-
- return strdup(lslash+1);
-}
-
-static const char PROPCHAR[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,._+*#?-";
-static const char UNITCHAR[] = "0123456789abcdef,";
-
-static int check_node_name(const char *name)
-{
- const char *atpos;
- int basenamelen;
+ plen = strlen(ppath);
- atpos = strrchr(name, '@');
+ if (!strneq(ppath, cpath, plen))
+ die("Path \"%s\" is not valid as a child of \"%s\"\n",
+ cpath, ppath);
- if (atpos)
- basenamelen = atpos - name;
- else
- basenamelen = strlen(name);
-
- if (strspn(name, PROPCHAR) < basenamelen)
- return -1;
+ /* root node is a special case */
+ if (!streq(ppath, "/"))
+ plen++;
- if (atpos
- && ((basenamelen + 1 + strspn(atpos+1, UNITCHAR)) < strlen(name)))
- return -1;
-
- return basenamelen;
+ return strdup(cpath + plen);
}
static struct node *unflatten_tree(struct inbuf *dtbuf,
struct inbuf *strbuf,
- const char *parent_path, int flags)
+ const char *parent_flatname, int flags)
{
struct node *node;
- u32 val;
+ char *flatname;
+ uint32_t val;
node = build_node(NULL, NULL);
- if (flags & FTF_FULLPATH) {
- node->fullpath = flat_read_string(dtbuf);
- node->name = nodename_from_path(parent_path, node->fullpath);
-
- if (! node->name)
- die("Path \"%s\" is not valid as a child of \"%s\"\n",
- node->fullpath, parent_path);
- } else {
- node->name = flat_read_string(dtbuf);
- node->fullpath = join_path(parent_path, node->name);
- }
+ flatname = flat_read_string(dtbuf);
- node->basenamelen = check_node_name(node->name);
- if (node->basenamelen < 0) {
- fprintf(stderr, "Warning \"%s\" has incorrect format\n", node->name);
- }
+ if (flags & FTF_FULLPATH)
+ node->name = nodename_from_path(parent_flatname, flatname);
+ else
+ node->name = flatname;
do {
struct property *prop;
@@ -795,8 +745,7 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
break;
case FDT_BEGIN_NODE:
- child = unflatten_tree(dtbuf,strbuf, node->fullpath,
- flags);
+ child = unflatten_tree(dtbuf,strbuf, flatname, flags);
add_child(node, child);
break;
@@ -825,10 +774,11 @@ static struct node *unflatten_tree(struct inbuf *dtbuf,
}
-struct boot_info *dt_from_blob(FILE *f)
+struct boot_info *dt_from_blob(const char *fname)
{
- u32 magic, totalsize, version, size_str, size_dt;
- u32 off_dt, off_str, off_mem_rsvmap;
+ struct dtc_file *dtcf;
+ uint32_t magic, totalsize, version, size_dt, boot_cpuid_phys;
+ uint32_t off_dt, off_str, off_mem_rsvmap;
int rc;
char *blob;
struct fdt_header *fdt;
@@ -838,54 +788,56 @@ struct boot_info *dt_from_blob(FILE *f)
int sizeleft;
struct reserve_info *reservelist;
struct node *tree;
- u32 val;
+ uint32_t val;
int flags = 0;
- rc = fread(&magic, sizeof(magic), 1, f);
- if (ferror(f))
+ dtcf = dtc_open_file(fname, NULL);
+
+ rc = fread(&magic, sizeof(magic), 1, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob magic number: %s\n",
strerror(errno));
if (rc < 1) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF reading DT blob magic number\n");
else
die("Mysterious short read reading magic number\n");
}
- magic = be32_to_cpu(magic);
+ magic = fdt32_to_cpu(magic);
if (magic != FDT_MAGIC)
die("Blob has incorrect magic number\n");
- rc = fread(&totalsize, sizeof(totalsize), 1, f);
- if (ferror(f))
+ rc = fread(&totalsize, sizeof(totalsize), 1, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob size: %s\n", strerror(errno));
if (rc < 1) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF reading DT blob size\n");
else
die("Mysterious short read reading blob size\n");
}
- totalsize = be32_to_cpu(totalsize);
+ totalsize = fdt32_to_cpu(totalsize);
if (totalsize < FDT_V1_SIZE)
die("DT blob size (%d) is too small\n", totalsize);
blob = xmalloc(totalsize);
fdt = (struct fdt_header *)blob;
- fdt->magic = cpu_to_be32(magic);
- fdt->totalsize = cpu_to_be32(totalsize);
+ fdt->magic = cpu_to_fdt32(magic);
+ fdt->totalsize = cpu_to_fdt32(totalsize);
sizeleft = totalsize - sizeof(magic) - sizeof(totalsize);
p = blob + sizeof(magic) + sizeof(totalsize);
while (sizeleft) {
- if (feof(f))
+ if (feof(dtcf->file))
die("EOF before reading %d bytes of DT blob\n",
totalsize);
- rc = fread(p, 1, sizeleft, f);
- if (ferror(f))
+ rc = fread(p, 1, sizeleft, dtcf->file);
+ if (ferror(dtcf->file))
die("Error reading DT blob: %s\n",
strerror(errno));
@@ -893,19 +845,11 @@ struct boot_info *dt_from_blob(FILE *f)
p += rc;
}
- off_dt = be32_to_cpu(fdt->off_dt_struct);
- off_str = be32_to_cpu(fdt->off_dt_strings);
- off_mem_rsvmap = be32_to_cpu(fdt->off_mem_rsvmap);
- version = be32_to_cpu(fdt->version);
-
- fprintf(stderr, "\tmagic:\t\t\t0x%x\n", magic);
- fprintf(stderr, "\ttotalsize:\t\t%d\n", totalsize);
- fprintf(stderr, "\toff_dt_struct:\t\t0x%x\n", off_dt);
- fprintf(stderr, "\toff_dt_strings:\t\t0x%x\n", off_str);
- fprintf(stderr, "\toff_mem_rsvmap:\t\t0x%x\n", off_mem_rsvmap);
- fprintf(stderr, "\tversion:\t\t0x%x\n", version );
- fprintf(stderr, "\tlast_comp_version:\t0x%x\n",
- be32_to_cpu(fdt->last_comp_version));
+ off_dt = fdt32_to_cpu(fdt->off_dt_struct);
+ off_str = fdt32_to_cpu(fdt->off_dt_strings);
+ off_mem_rsvmap = fdt32_to_cpu(fdt->off_mem_rsvmap);
+ version = fdt32_to_cpu(fdt->version);
+ boot_cpuid_phys = fdt32_to_cpu(fdt->boot_cpuid_phys);
if (off_mem_rsvmap >= totalsize)
die("Mem Reserve structure offset exceeds total size\n");
@@ -916,21 +860,17 @@ struct boot_info *dt_from_blob(FILE *f)
if (off_str > totalsize)
die("String table offset exceeds total size\n");
- if (version >= 2)
- fprintf(stderr, "\tboot_cpuid_phys:\t0x%x\n",
- be32_to_cpu(fdt->boot_cpuid_phys));
-
- size_str = -1;
if (version >= 3) {
- size_str = be32_to_cpu(fdt->size_dt_strings);
- fprintf(stderr, "\tsize_dt_strings:\t%d\n", size_str);
+ uint32_t size_str = fdt32_to_cpu(fdt->size_dt_strings);
if (off_str+size_str > totalsize)
die("String table extends past total size\n");
+ inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
+ } else {
+ inbuf_init(&strbuf, blob + off_str, blob + totalsize);
}
if (version >= 17) {
- size_dt = be32_to_cpu(fdt->size_dt_struct);
- fprintf(stderr, "\tsize_dt_struct:\t\t%d\n", size_dt);
+ size_dt = fdt32_to_cpu(fdt->size_dt_struct);
if (off_dt+size_dt > totalsize)
die("Structure block extends past total size\n");
}
@@ -944,10 +884,6 @@ struct boot_info *dt_from_blob(FILE *f)
inbuf_init(&memresvbuf,
blob + off_mem_rsvmap, blob + totalsize);
inbuf_init(&dtbuf, blob + off_dt, blob + totalsize);
- if (size_str >= 0)
- inbuf_init(&strbuf, blob + off_str, blob + off_str + size_str);
- else
- inbuf_init(&strbuf, blob + off_str, blob + totalsize);
reservelist = flat_read_mem_reserve(&memresvbuf);
@@ -964,5 +900,7 @@ struct boot_info *dt_from_blob(FILE *f)
free(blob);
- return build_boot_info(reservelist, tree);
+ dtc_close_file(dtcf);
+
+ return build_boot_info(reservelist, tree, boot_cpuid_phys);
}
diff --git a/arch/powerpc/boot/dtc-src/fstree.c b/arch/powerpc/boot/dtc-src/fstree.c
index 2a160a46998..766b2694d93 100644
--- a/arch/powerpc/boot/dtc-src/fstree.c
+++ b/arch/powerpc/boot/dtc-src/fstree.c
@@ -31,8 +31,8 @@ static struct node *read_fstree(const char *dirname)
struct node *tree;
d = opendir(dirname);
- if (! d)
- die("opendir(): %s\n", strerror(errno));
+ if (!d)
+ die("Couldn't opendir() \"%s\": %s\n", dirname, strerror(errno));
tree = build_node(NULL, NULL);
@@ -87,8 +87,6 @@ struct boot_info *dt_from_fs(const char *dirname)
tree = read_fstree(dirname);
tree = name_node(tree, "", NULL);
- fill_fullpaths(tree, "");
-
- return build_boot_info(NULL, tree);
+ return build_boot_info(NULL, tree, 0);
}
diff --git a/arch/powerpc/boot/dtc-src/libfdt_env.h b/arch/powerpc/boot/dtc-src/libfdt_env.h
new file mode 100644
index 00000000000..449bf602daf
--- /dev/null
+++ b/arch/powerpc/boot/dtc-src/libfdt_env.h
@@ -0,0 +1,23 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#define _B(n) ((unsigned long long)((uint8_t *)&x)[n])
+static inline uint32_t fdt32_to_cpu(uint32_t x)
+{
+ return (_B(0) << 24) | (_B(1) << 16) | (_B(2) << 8) | _B(3);
+}
+#define cpu_to_fdt32(x) fdt32_to_cpu(x)
+
+static inline uint64_t fdt64_to_cpu(uint64_t x)
+{
+ return (_B(0) << 56) | (_B(1) << 48) | (_B(2) << 40) | (_B(3) << 32)
+ | (_B(4) << 24) | (_B(5) << 16) | (_B(6) << 8) | _B(7);
+}
+#define cpu_to_fdt64(x) fdt64_to_cpu(x)
+#undef _B
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/arch/powerpc/boot/dtc-src/livetree.c b/arch/powerpc/boot/dtc-src/livetree.c
index 6ba0846b431..0ca3de550b3 100644
--- a/arch/powerpc/boot/dtc-src/livetree.c
+++ b/arch/powerpc/boot/dtc-src/livetree.c
@@ -115,6 +115,7 @@ void add_child(struct node *parent, struct node *child)
struct node **p;
child->next_sibling = NULL;
+ child->parent = parent;
p = &parent->children;
while (*p)
@@ -123,7 +124,8 @@ void add_child(struct node *parent, struct node *child)
*p = child;
}
-struct reserve_info *build_reserve_entry(u64 address, u64 size, char *label)
+struct reserve_info *build_reserve_entry(uint64_t address, uint64_t size,
+ char *label)
{
struct reserve_info *new = xmalloc(sizeof(*new));
@@ -165,13 +167,14 @@ struct reserve_info *add_reserve_entry(struct reserve_info *list,
}
struct boot_info *build_boot_info(struct reserve_info *reservelist,
- struct node *tree)
+ struct node *tree, uint32_t boot_cpuid_phys)
{
struct boot_info *bi;
bi = xmalloc(sizeof(*bi));
bi->reservelist = reservelist;
bi->dt = tree;
+ bi->boot_cpuid_phys = boot_cpuid_phys;
return bi;
}
@@ -202,7 +205,7 @@ struct property *get_property(struct node *node, const char *propname)
cell_t propval_cell(struct property *prop)
{
assert(prop->val.len == sizeof(cell_t));
- return be32_to_cpu(*((cell_t *)prop->val.val));
+ return fdt32_to_cpu(*((cell_t *)prop->val.val));
}
struct node *get_subnode(struct node *node, const char *nodename)
diff --git a/arch/powerpc/boot/dtc-src/srcpos.c b/arch/powerpc/boot/dtc-src/srcpos.c
index 352b0fe06fd..9641b7628b4 100644
--- a/arch/powerpc/boot/dtc-src/srcpos.c
+++ b/arch/powerpc/boot/dtc-src/srcpos.c
@@ -20,86 +20,97 @@
#include "dtc.h"
#include "srcpos.h"
-
-/*
- * Record the complete unique set of opened file names.
- * Primarily used to cache source position file names.
- */
-#define MAX_N_FILE_NAMES (100)
-
-const char *file_names[MAX_N_FILE_NAMES];
-static int n_file_names = 0;
-
/*
* Like yylineno, this is the current open file pos.
*/
-int srcpos_filenum = -1;
-
+struct dtc_file *srcpos_file;
-
-FILE *dtc_open_file(const char *fname)
+static int dtc_open_one(struct dtc_file *file,
+ const char *search,
+ const char *fname)
{
- FILE *f;
+ char *fullname;
- if (lookup_file_name(fname, 1) < 0)
- die("Too many files opened\n");
+ if (search) {
+ fullname = xmalloc(strlen(search) + strlen(fname) + 2);
- if (streq(fname, "-"))
- f = stdin;
- else
- f = fopen(fname, "r");
+ strcpy(fullname, search);
+ strcat(fullname, "/");
+ strcat(fullname, fname);
+ } else {
+ fullname = strdup(fname);
+ }
- if (! f)
- die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
+ file->file = fopen(fullname, "r");
+ if (!file->file) {
+ free(fullname);
+ return 0;
+ }
- return f;
+ file->name = fullname;
+ return 1;
}
+struct dtc_file *dtc_open_file(const char *fname,
+ const struct search_path *search)
+{
+ static const struct search_path default_search = { NULL, NULL, NULL };
-/*
- * Locate and optionally add filename fname in the file_names[] array.
- *
- * If the filename is currently not in the array and the boolean
- * add_it is non-zero, an attempt to add the filename will be made.
- *
- * Returns;
- * Index [0..MAX_N_FILE_NAMES) where the filename is kept
- * -1 if the name can not be recorded
- */
+ struct dtc_file *file;
+ const char *slash;
-int lookup_file_name(const char *fname, int add_it)
-{
- int i;
+ file = xmalloc(sizeof(struct dtc_file));
- for (i = 0; i < n_file_names; i++) {
- if (strcmp(file_names[i], fname) == 0)
- return i;
+ slash = strrchr(fname, '/');
+ if (slash) {
+ char *dir = xmalloc(slash - fname + 1);
+
+ memcpy(dir, fname, slash - fname);
+ dir[slash - fname] = 0;
+ file->dir = dir;
+ } else {
+ file->dir = NULL;
}
- if (add_it) {
- if (n_file_names < MAX_N_FILE_NAMES) {
- file_names[n_file_names] = strdup(fname);
- return n_file_names++;
- }
+ if (streq(fname, "-")) {
+ file->name = "stdin";
+ file->file = stdin;
+ return file;
}
- return -1;
-}
+ if (fname[0] == '/') {
+ file->file = fopen(fname, "r");
+ if (!file->file)
+ goto fail;
+
+ file->name = strdup(fname);
+ return file;
+ }
+ if (!search)
+ search = &default_search;
-const char *srcpos_filename_for_num(int filenum)
-{
- if (0 <= filenum && filenum < n_file_names) {
- return file_names[filenum];
+ while (search) {
+ if (dtc_open_one(file, search->dir, fname))
+ return file;
+
+ if (errno != ENOENT)
+ goto fail;
+
+ search = search->next;
}
- return 0;
+fail:
+ die("Couldn't open \"%s\": %s\n", fname, strerror(errno));
}
-
-const char *srcpos_get_filename(void)
+void dtc_close_file(struct dtc_file *file)
{
- return srcpos_filename_for_num(srcpos_filenum);
+ if (fclose(file->file))
+ die("Error closing \"%s\": %s\n", file->name, strerror(errno));
+
+ free(file->dir);
+ free(file);
}
diff --git a/arch/powerpc/boot/dtc-src/srcpos.h b/arch/powerpc/boot/dtc-src/srcpos.h
index ce7ab5ba5b4..e17c7c04db8 100644
--- a/arch/powerpc/boot/dtc-src/srcpos.h
+++ b/arch/powerpc/boot/dtc-src/srcpos.h
@@ -22,13 +22,21 @@
* array of all opened filenames.
*/
+#include <stdio.h>
+
+struct dtc_file {
+ char *dir;
+ const char *name;
+ FILE *file;
+};
+
#if ! defined(YYLTYPE) && ! defined(YYLTYPE_IS_DECLARED)
typedef struct YYLTYPE {
int first_line;
int first_column;
int last_line;
int last_column;
- int filenum;
+ struct dtc_file *file;
} YYLTYPE;
#define YYLTYPE_IS_DECLARED 1
@@ -48,7 +56,7 @@ typedef struct YYLTYPE {
(Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
(Current).last_line = YYRHSLOC (Rhs, N).last_line; \
(Current).last_column = YYRHSLOC (Rhs, N).last_column; \
- (Current).filenum = YYRHSLOC (Rhs, N).filenum; \
+ (Current).file = YYRHSLOC (Rhs, N).file; \
} \
else \
{ \
@@ -56,20 +64,22 @@ typedef struct YYLTYPE {
YYRHSLOC (Rhs, 0).last_line; \
(Current).first_column = (Current).last_column = \
YYRHSLOC (Rhs, 0).last_column; \
- (Current).filenum = YYRHSLOC (Rhs, 0).filenum; \
+ (Current).file = YYRHSLOC (Rhs, 0).file; \
} \
while (YYID (0))
extern void yyerror(char const *);
+extern void yyerrorf(char const *, ...) __attribute__((format(printf, 1, 2)));
-extern int srcpos_filenum;
+extern struct dtc_file *srcpos_file;
-extern int push_input_file(const char *filename);
-extern int pop_input_file(void);
+struct search_path {
+ const char *dir; /* NULL for current directory */
+ struct search_path *prev, *next;
+};
-extern FILE *dtc_open_file(const char *fname);
-extern int lookup_file_name(const char *fname, int add_it);
-extern const char *srcpos_filename_for_num(int filenum);
-const char *srcpos_get_filename(void);
+extern struct dtc_file *dtc_open_file(const char *fname,
+ const struct search_path *search);
+extern void dtc_close_file(struct dtc_file *file);
diff --git a/arch/powerpc/boot/dtc-src/treesource.c b/arch/powerpc/boot/dtc-src/treesource.c
index a6a77679763..ebeb6eb2790 100644
--- a/arch/powerpc/boot/dtc-src/treesource.c
+++ b/arch/powerpc/boot/dtc-src/treesource.c
@@ -23,20 +23,23 @@
extern FILE *yyin;
extern int yyparse(void);
-extern void yyerror(char const *);
struct boot_info *the_boot_info;
+int treesource_error;
struct boot_info *dt_from_source(const char *fname)
{
the_boot_info = NULL;
+ treesource_error = 0;
- push_input_file(fname);
+ srcpos_file = dtc_open_file(fname, NULL);
+ yyin = srcpos_file->file;
if (yyparse() != 0)
- return NULL;
+ die("Unable to parse input tree\n");
- fill_fullpaths(the_boot_info->dt, "");
+ if (treesource_error)
+ die("Syntax error parsing input tree\n");
return the_boot_info;
}
@@ -144,7 +147,7 @@ static void write_propval_cells(FILE *f, struct data val)
m = m->next;
}
- fprintf(f, "0x%x", be32_to_cpu(*cp++));
+ fprintf(f, "0x%x", fdt32_to_cpu(*cp++));
if ((void *)cp >= propend)
break;
fprintf(f, " ");
@@ -173,7 +176,7 @@ static void write_propval_bytes(FILE *f, struct data val)
}
fprintf(f, "%02hhx", *bp++);
- if ((void *)bp >= propend)
+ if ((const void *)bp >= propend)
break;
fprintf(f, " ");
}
diff --git a/arch/powerpc/boot/dtc-src/version_gen.h b/arch/powerpc/boot/dtc-src/version_gen.h
index 6c343031538..658ff42429d 100644
--- a/arch/powerpc/boot/dtc-src/version_gen.h
+++ b/arch/powerpc/boot/dtc-src/version_gen.h
@@ -1 +1 @@
-#define DTC_VERSION "DTC 1.0.0-gd6f9b62f"
+#define DTC_VERSION "DTC 1.2.0"
diff --git a/arch/powerpc/boot/dts/arches.dts b/arch/powerpc/boot/dts/arches.dts
new file mode 100644
index 00000000000..d9113b1e8c1
--- /dev/null
+++ b/arch/powerpc/boot/dts/arches.dts
@@ -0,0 +1,293 @@
+/*
+ * Device Tree Source for AMCC Arches (dual 460GT board)
+ *
+ * (C) Copyright 2008 Applied Micro Circuits Corporation
+ * Victor Gallardo <vgallardo@amcc.com>
+ * Adam Graham <agraham@amcc.com>
+ *
+ * Based on the glacier.dts file
+ * Stefan Roese <sr@denx.de>
+ * Copyright 2008 DENX Software Engineering
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+/dts-v1/;
+
+/ {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ model = "amcc,arches";
+ compatible = "amcc,arches";
+ dcr-parent = <&{/cpus/cpu@0}>;
+
+ aliases {
+ ethernet0 = &EMAC0;
+ ethernet1 = &EMAC1;
+ ethernet2 = &EMAC2;
+ serial0 = &UART0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ model = "PowerPC,460GT";
+ reg = <0x00000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ i-cache-line-size = <32>;
+ d-cache-line-size = <32>;
+ i-cache-size = <32768>;
+ d-cache-size = <32768>;
+ dcr-controller;
+ dcr-access-method = "native";
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by U-Boot */
+ };
+
+ UIC0: interrupt-controller0 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <0>;
+ dcr-reg = <0x0c0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ };
+
+ UIC1: interrupt-controller1 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <1>;
+ dcr-reg = <0x0d0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x1e 0x4 0x1f 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC2: interrupt-controller2 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <2>;
+ dcr-reg = <0x0e0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0xa 0x4 0xb 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ UIC3: interrupt-controller3 {
+ compatible = "ibm,uic-460gt","ibm,uic";
+ interrupt-controller;
+ cell-index = <3>;
+ dcr-reg = <0x0f0 0x009>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <0x10 0x4 0x11 0x4>; /* cascade */
+ interrupt-parent = <&UIC0>;
+ };
+
+ SDR0: sdr {
+ compatible = "ibm,sdr-460gt";
+ dcr-reg = <0x00e 0x002>;
+ };
+
+ CPR0: cpr {
+ compatible = "ibm,cpr-460gt";
+ dcr-reg = <0x00c 0x002>;
+ };
+
+ plb {
+ compatible = "ibm,plb-460gt", "ibm,plb4";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ SDRAM0: sdram {
+ compatible = "ibm,sdram-460gt", "ibm,sdram-405gp";
+ dcr-reg = <0x010 0x002>;
+ };
+
+ MAL0: mcmal {
+ compatible = "ibm,mcmal-460gt", "ibm,mcmal2";
+ dcr-reg = <0x180 0x062>;
+ num-tx-chans = <3>;
+ num-rx-chans = <24>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-parent = <&UIC2>;
+ interrupts = < /*TXEOB*/ 0x6 0x4
+ /*RXEOB*/ 0x7 0x4
+ /*SERR*/ 0x3 0x4
+ /*TXDE*/ 0x4 0x4
+ /*RXDE*/ 0x5 0x4>;
+ desc-base-addr-high = <0x8>;
+ };
+
+ POB0: opb {
+ compatible = "ibm,opb-460gt", "ibm,opb";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0xb0000000 0x00000004 0xb0000000 0x50000000>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+
+ EBC0: ebc {
+ compatible = "ibm,ebc-460gt", "ibm,ebc";
+ dcr-reg = <0x012 0x002>;
+ #address-cells = <2>;
+ #size-cells = <1>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ /* ranges property is supplied by U-Boot */
+ interrupts = <0x6 0x4>;
+ interrupt-parent = <&UIC1>;
+ };
+
+ UART0: serial@ef600300 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0xef600300 0x00000008>;
+ virtual-reg = <0xef600300>;
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ current-speed = <0>; /* Filled in by U-Boot */
+ interrupt-parent = <&UIC1>;
+ interrupts = <0x1 0x4>;
+ };
+
+ IIC0: i2c@ef600700 {
+ compatible = "ibm,iic-460gt", "ibm,iic";
+ reg = <0xef600700 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x2 0x4>;
+ };
+
+ IIC1: i2c@ef600800 {
+ compatible = "ibm,iic-460gt", "ibm,iic";
+ reg = <0xef600800 0x00000014>;
+ interrupt-parent = <&UIC0>;
+ interrupts = <0x3 0x4>;
+ };
+
+ TAH0: emac-tah@ef601350 {
+ compatible = "ibm,tah-460gt", "ibm,tah";
+ reg = <0xef601350 0x00000030>;
+ };
+
+ TAH1: emac-tah@ef601450 {
+ compatible = "ibm,tah-460gt", "ibm,tah";
+ reg = <0xef601450 0x00000030>;
+ };
+
+ EMAC0: ethernet@ef600e00 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4sync";
+ interrupt-parent = <&EMAC0>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC2 0x10 0x4
+ /*Wake*/ 0x1 &UIC2 0x14 0x4>;
+ reg = <0xef600e00 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <0>;
+ mal-rx-channel = <0>;
+ cell-index = <0>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "sgmii";
+ phy-map = <0xffffffff>;
+ gpcs-address = <0x0000000a>;
+ tah-device = <&TAH0>;
+ tah-channel = <0>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ };
+
+ EMAC1: ethernet@ef600f00 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4sync";
+ interrupt-parent = <&EMAC1>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC2 0x11 0x4
+ /*Wake*/ 0x1 &UIC2 0x15 0x4>;
+ reg = <0xef600f00 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <1>;
+ mal-rx-channel = <8>;
+ cell-index = <1>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "sgmii";
+ phy-map = <0x00000000>;
+ gpcs-address = <0x0000000b>;
+ tah-device = <&TAH1>;
+ tah-channel = <1>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ mdio-device = <&EMAC0>;
+ };
+
+ EMAC2: ethernet@ef601100 {
+ device_type = "network";
+ compatible = "ibm,emac-460gt", "ibm,emac4sync";
+ interrupt-parent = <&EMAC2>;
+ interrupts = <0x0 0x1>;
+ #interrupt-cells = <1>;
+ #address-cells = <0>;
+ #size-cells = <0>;
+ interrupt-map = </*Status*/ 0x0 &UIC2 0x12 0x4
+ /*Wake*/ 0x1 &UIC2 0x16 0x4>;
+ reg = <0xef601100 0x000000c4>;
+ local-mac-address = [000000000000]; /* Filled in by U-Boot */
+ mal-device = <&MAL0>;
+ mal-tx-channel = <2>;
+ mal-rx-channel = <16>;
+ cell-index = <2>;
+ max-frame-size = <9000>;
+ rx-fifo-size = <4096>;
+ tx-fifo-size = <2048>;
+ phy-mode = "sgmii";
+ phy-map = <0x00000001>;
+ gpcs-address = <0x0000000C>;
+ has-inverted-stacr-oc;
+ has-new-stacr-staopc;
+ mdio-device = <&EMAC0>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/asp834x-redboot.dts b/arch/powerpc/boot/dts/asp834x-redboot.dts
index 8b1bb0e4190..6235fca445d 100644
--- a/arch/powerpc/boot/dts/asp834x-redboot.dts
+++ b/arch/powerpc/boot/dts/asp834x-redboot.dts
@@ -130,24 +130,28 @@
dma-channel@0 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8347-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts
new file mode 100644
index 00000000000..6ed608322dd
--- /dev/null
+++ b/arch/powerpc/boot/dts/gef_sbc610.dts
@@ -0,0 +1,293 @@
+/*
+ * GE Fanuc SBC610 Device Tree Source
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: SBS CM6 Device Tree Source
+ * Copyright 2007 SBS Technologies GmbH & Co. KG
+ * And: mpc8641_hpcn.dts (MPC8641 HPCN Device Tree Source)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ */
+
+/*
+ * Compiled with dtc -I dts -O dtb -o gef_sbc610.dtb gef_sbc610.dts
+ */
+
+/dts-v1/;
+
+/ {
+ model = "GEF_SBC610";
+ compatible = "gef,sbc610";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &enet0;
+ ethernet1 = &enet1;
+ serial0 = &serial0;
+ serial1 = &serial1;
+ pci0 = &pci0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8641@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <32>; // 32 bytes
+ i-cache-line-size = <32>; // 32 bytes
+ d-cache-size = <32768>; // L1, 32K
+ i-cache-size = <32768>; // L1, 32K
+ timebase-frequency = <0>; // From uboot
+ bus-frequency = <0>; // From uboot
+ clock-frequency = <0>; // From uboot
+ };
+ PowerPC,8641@1 {
+ device_type = "cpu";
+ reg = <1>;
+ d-cache-line-size = <32>; // 32 bytes
+ i-cache-line-size = <32>; // 32 bytes
+ d-cache-size = <32768>; // L1, 32K
+ i-cache-size = <32768>; // L1, 32K
+ timebase-frequency = <0>; // From uboot
+ bus-frequency = <0>; // From uboot
+ clock-frequency = <0>; // From uboot
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x40000000>; // set by uboot
+ };
+
+ localbus@fef05000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8641-localbus", "simple-bus";
+ reg = <0xf8005000 0x1000>;
+ interrupts = <19 2>;
+ interrupt-parent = <&mpic>;
+
+ ranges = <0 0 0xff000000 0x01000000 // 16MB Boot flash
+ 1 0 0xe8000000 0x08000000 // Paged Flash 0
+ 2 0 0xe0000000 0x08000000 // Paged Flash 1
+ 3 0 0xfc100000 0x00020000 // NVRAM
+ 4 0 0xfc000000 0x00008000 // FPGA
+ 5 0 0xfc008000 0x00008000 // AFIX FPGA
+ 6 0 0xfd000000 0x00800000 // IO FPGA (8-bit)
+ 7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit)
+
+ fpga@4,0 {
+ compatible = "gef,fpga-regs";
+ reg = <0x4 0x0 0x40>;
+ };
+ gef_pic: pic@4,4000 {
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "gef,fpga-pic";
+ reg = <0x4 0x4000 0x20>;
+ interrupts = <0x8
+ 0x9>;
+ interrupt-parent = <&mpic>;
+
+ };
+ };
+
+ soc@fef00000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ compatible = "simple-bus";
+ ranges = <0x0 0xfef00000 0x00100000>;
+ reg = <0xfef00000 0x100000>; // CCSRBAR 1M
+ bus-frequency = <0>;
+
+ i2c1: i2c@3000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3000 0x100>;
+ interrupts = <0x2b 0x2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+
+ eti@6b {
+ compatible = "dallas,ds1682";
+ reg = <0x6b>;
+ };
+ };
+
+ i2c2: i2c@3100 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl-i2c";
+ reg = <0x3100 0x100>;
+ interrupts = <0x2b 0x2>;
+ interrupt-parent = <&mpic>;
+ dfsrr;
+ };
+
+ dma@21300 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma";
+ reg = <0x21300 0x4>;
+ ranges = <0x0 0x21100 0x200>;
+ cell-index = <0>;
+ dma-channel@0 {
+ compatible = "fsl,mpc8641-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x0 0x80>;
+ cell-index = <0>;
+ interrupt-parent = <&mpic>;
+ interrupts = <20 2>;
+ };
+ dma-channel@80 {
+ compatible = "fsl,mpc8641-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x80 0x80>;
+ cell-index = <1>;
+ interrupt-parent = <&mpic>;
+ interrupts = <21 2>;
+ };
+ dma-channel@100 {
+ compatible = "fsl,mpc8641-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x100 0x80>;
+ cell-index = <2>;
+ interrupt-parent = <&mpic>;
+ interrupts = <22 2>;
+ };
+ dma-channel@180 {
+ compatible = "fsl,mpc8641-dma-channel",
+ "fsl,eloplus-dma-channel";
+ reg = <0x180 0x80>;
+ cell-index = <3>;
+ interrupt-parent = <&mpic>;
+ interrupts = <23 2>;
+ };
+ };
+
+ mdio@24520 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,gianfar-mdio";
+ reg = <0x24520 0x20>;
+
+ phy0: ethernet-phy@0 {
+ interrupt-parent = <&gef_pic>;
+ interrupts = <0x9 0x4>;
+ reg = <1>;
+ };
+ phy2: ethernet-phy@2 {
+ interrupt-parent = <&gef_pic>;
+ interrupts = <0x8 0x4>;
+ reg = <3>;
+ };
+ };
+
+ enet0: ethernet@24000 {
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x24000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy0>;
+ phy-connection-type = "gmii";
+ };
+
+ enet1: ethernet@26000 {
+ device_type = "network";
+ model = "eTSEC";
+ compatible = "gianfar";
+ reg = <0x26000 0x1000>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <0x1f 0x2 0x20 0x2 0x21 0x2>;
+ interrupt-parent = <&mpic>;
+ phy-handle = <&phy2>;
+ phy-connection-type = "gmii";
+ };
+
+ serial0: serial@4500 {
+ cell-index = <0>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4500 0x100>;
+ clock-frequency = <0>;
+ interrupts = <0x2a 0x2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ serial1: serial@4600 {
+ cell-index = <1>;
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0x4600 0x100>;
+ clock-frequency = <0>;
+ interrupts = <0x1c 0x2>;
+ interrupt-parent = <&mpic>;
+ };
+
+ mpic: pic@40000 {
+ clock-frequency = <0>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <0x40000 0x40000>;
+ compatible = "chrp,open-pic";
+ device_type = "open-pic";
+ };
+
+ global-utilities@e0000 {
+ compatible = "fsl,mpc8641-guts";
+ reg = <0xe0000 0x1000>;
+ fsl,has-rstcr;
+ };
+ };
+
+ pci0: pcie@fef08000 {
+ compatible = "fsl,mpc8641-pcie";
+ device_type = "pci";
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <0xfef08000 0x1000>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x40000000
+ 0x01000000 0x0 0x00000000 0xfe000000 0x0 0x00400000>;
+ clock-frequency = <33333333>;
+ interrupt-parent = <&mpic>;
+ interrupts = <0x18 0x2>;
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map = <
+ 0x0000 0x0 0x0 0x1 &mpic 0x0 0x1
+ 0x0000 0x0 0x0 0x2 &mpic 0x1 0x1
+ 0x0000 0x0 0x0 0x3 &mpic 0x2 0x1
+ 0x0000 0x0 0x0 0x4 &mpic 0x3 0x1
+ >;
+
+ pcie@0 {
+ reg = <0 0 0 0 0>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ device_type = "pci";
+ ranges = <0x02000000 0x0 0x80000000
+ 0x02000000 0x0 0x80000000
+ 0x0 0x40000000
+
+ 0x01000000 0x0 0x00000000
+ 0x01000000 0x0 0x00000000
+ 0x0 0x00400000>;
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts
index 24cf0dba120..f3787a27f63 100644
--- a/arch/powerpc/boot/dts/glacier.dts
+++ b/arch/powerpc/boot/dts/glacier.dts
@@ -14,7 +14,7 @@
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,glacier";
- compatible = "amcc,glacier", "amcc,canyonlands";
+ compatible = "amcc,glacier";
dcr-parent = <&{/cpus/cpu@0}>;
aliases {
diff --git a/arch/powerpc/boot/dts/mgcoge.dts b/arch/powerpc/boot/dts/mgcoge.dts
new file mode 100644
index 00000000000..633255a9755
--- /dev/null
+++ b/arch/powerpc/boot/dts/mgcoge.dts
@@ -0,0 +1,174 @@
+/*
+ * Device Tree for the MGCOGE plattform from keymile
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+/ {
+ model = "MGCOGE";
+ compatible = "keymile,mgcoge";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &eth0;
+ serial0 = &smc2;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8247@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <32>;
+ i-cache-line-size = <32>;
+ d-cache-size = <16384>;
+ i-cache-size = <16384>;
+ timebase-frequency = <0>; /* Filled in by U-Boot */
+ clock-frequency = <0>; /* Filled in by U-Boot */
+ bus-frequency = <0>; /* Filled in by U-Boot */
+ };
+ };
+
+ localbus@f0010100 {
+ compatible = "fsl,mpc8247-localbus",
+ "fsl,pq2-localbus",
+ "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0xf0010100 0x40>;
+
+ ranges = <0 0 0xfe000000 0x00400000
+ 5 0 0x50000000 0x20000000
+ >; /* Filled in by U-Boot */
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0x0 0x400000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <1>;
+ device-width = <1>;
+ partition@0 {
+ label = "u-boot";
+ reg = <0 0x40000>;
+ };
+ partition@40000 {
+ label = "env";
+ reg = <0x40000 0x20000>;
+ };
+ partition@60000 {
+ label = "kernel";
+ reg = <0x60000 0x220000>;
+ };
+ partition@280000 {
+ label = "dtb";
+ reg = <0x280000 0x20000>;
+ };
+ };
+
+ flash@5,0 {
+ compatible = "cfi-flash";
+ reg = <5 0x0 0x2000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <2>;
+ device-width = <2>;
+ partition@0 {
+ label = "ramdisk";
+ reg = <0 0x7a0000>;
+ };
+ partition@7a0000 {
+ label = "user";
+ reg = <0x7a0000 0x1860000>;
+ };
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0>; /* Filled in by U-Boot */
+ };
+
+ soc@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8247-immr", "fsl,pq2-soc", "simple-bus";
+ ranges = <0x00000000 0xf0000000 0x00053000>;
+
+ // Temporary until code stops depending on it.
+ device_type = "soc";
+
+ cpm@119c0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ compatible = "fsl,mpc8247-cpm", "fsl,cpm2",
+ "simple-bus";
+ reg = <0x119c0 0x30>;
+ ranges;
+
+ muram {
+ compatible = "fsl,cpm-muram";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0 0x10000>;
+
+ data@0 {
+ compatible = "fsl,cpm-muram-data";
+ reg = <0x80 0x1f80 0x9800 0x800>;
+ };
+ };
+
+ brg@119f0 {
+ compatible = "fsl,mpc8247-brg",
+ "fsl,cpm2-brg",
+ "fsl,cpm-brg";
+ reg = <0x119f0 0x10 0x115f0 0x10>;
+ };
+
+ /* Monitor port/SMC2 */
+ smc2: serial@11a90 {
+ device_type = "serial";
+ compatible = "fsl,mpc8247-smc-uart",
+ "fsl,cpm2-smc-uart";
+ reg = <0x11a90 0x20 0x88fc 0x02>;
+ interrupts = <5 8>;
+ interrupt-parent = <&PIC>;
+ fsl,cpm-brg = <2>;
+ fsl,cpm-command = <0x21200000>;
+ current-speed = <0>; /* Filled in by U-Boot */
+ };
+
+ eth0: ethernet@11a60 {
+ device_type = "network";
+ compatible = "fsl,mpc8247-scc-enet",
+ "fsl,cpm2-scc-enet";
+ reg = <0x11a60 0x20 0x8300 0x100 0x11390 1>;
+ local-mac-address = [ 00 00 00 00 00 00 ]; /* Filled in by U-Boot */
+ interrupts = <43 8>;
+ interrupt-parent = <&PIC>;
+ linux,network-index = <0>;
+ fsl,cpm-command = <0xce00000>;
+ fixed-link = <0 0 10 0 0>;
+ };
+
+ };
+
+ PIC: interrupt-controller@10c00 {
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <0x10c00 0x80>;
+ compatible = "fsl,mpc8247-pic", "fsl,pq2-pic";
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mgsuvd.dts b/arch/powerpc/boot/dts/mgsuvd.dts
new file mode 100644
index 00000000000..e4fc53ab42b
--- /dev/null
+++ b/arch/powerpc/boot/dts/mgsuvd.dts
@@ -0,0 +1,163 @@
+/*
+ * MGSUVD Device Tree Source
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Heiko Schocher <hs@denx.de>
+ *
+ * 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.
+ */
+
+/dts-v1/;
+/ {
+ model = "MGSUVD";
+ compatible = "keymile,mgsuvd";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,852@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <16>;
+ i-cache-line-size = <16>;
+ d-cache-size = <8192>;
+ i-cache-size = <8192>;
+ timebase-frequency = <0>; /* Filled in by u-boot */
+ bus-frequency = <0>; /* Filled in by u-boot */
+ clock-frequency = <0>; /* Filled in by u-boot */
+ interrupts = <15 2>; /* decrementer interrupt */
+ interrupt-parent = <&PIC>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 0x4000000>; /* Filled in by u-boot */
+ };
+
+ localbus@fff00100 {
+ compatible = "fsl,mpc852-localbus", "fsl,pq1-localbus", "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ reg = <0xfff00100 0x40>;
+
+ ranges = <0 0 0xf0000000 0x01000000>; /* Filled in by u-boot */
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ bank-width = <1>;
+ device-width = <1>;
+ partition@0 {
+ label = "u-boot";
+ reg = <0 0x80000>;
+ };
+ partition@80000 {
+ label = "env";
+ reg = <0x80000 0x20000>;
+ };
+ partition@a0000 {
+ label = "kernel";
+ reg = <0xa0000 0x1e0000>;
+ };
+ partition@280000 {
+ label = "dtb";
+ reg = <0x280000 0x20000>;
+ };
+ partition@2a0000 {
+ label = "root";
+ reg = <0x2a0000 0x500000>;
+ };
+ partition@7a0000 {
+ label = "user";
+ reg = <0x7a0000 0x860000>;
+ };
+ };
+ };
+
+ soc@fff00000 {
+ compatible = "fsl,mpc852", "fsl,pq1-soc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "soc";
+ ranges = <0 0xfff00000 0x00004000>;
+
+ PIC: interrupt-controller@0 {
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0 24>;
+ compatible = "fsl,mpc852-pic", "fsl,pq1-pic";
+ };
+
+ cpm@9c0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc852-cpm", "fsl,cpm1", "simple-bus";
+ interrupts = <0>; /* cpm error interrupt */
+ interrupt-parent = <&CPM_PIC>;
+ reg = <0x9c0 10>;
+ ranges;
+
+ muram@2000 {
+ compatible = "fsl,cpm-muram";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x2000 0x2000>;
+
+ data@0 {
+ compatible = "fsl,cpm-muram-data";
+ reg = <0x800 0x1800>;
+ };
+ };
+
+ brg@9f0 {
+ compatible = "fsl,mpc852-brg",
+ "fsl,cpm1-brg",
+ "fsl,cpm-brg";
+ reg = <0x9f0 0x10>;
+ clock-frequency = <0>; /* Filled in by u-boot */
+ };
+
+ CPM_PIC: interrupt-controller@930 {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupts = <5 2 0 2>;
+ interrupt-parent = <&PIC>;
+ reg = <0x930 0x20>;
+ compatible = "fsl,cpm1-pic";
+ };
+
+ /* MON-1 */
+ serial@a80 {
+ device_type = "serial";
+ compatible = "fsl,cpm1-smc-uart";
+ reg = <0xa80 0x10 0x3fc0 0x40>;
+ interrupts = <4>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-brg = <1>;
+ fsl,cpm-command = <0x0090>;
+ current-speed = <0>; /* Filled in by u-boot */
+ };
+
+ ethernet@a40 {
+ device_type = "network";
+ compatible = "fsl,mpc866-scc-enet",
+ "fsl,cpm1-scc-enet";
+ reg = <0xa40 0x18 0x3e00 0x100>;
+ local-mac-address = [ 00 00 00 00 00 00 ]; /* Filled in by u-boot */
+ interrupts = <28>;
+ interrupt-parent = <&CPM_PIC>;
+ fsl,cpm-command = <0x80>;
+ fixed-link = <0 0 10 0 0>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index 1f9036c317b..c2b8dbfab79 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -403,7 +403,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0x80008500 0x100>;
+ reg = <0x80008500 0x100 /* internal registers */
+ 0x80008300 0x8>; /* config space access registers */
compatible = "fsl,mpc5121-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts
index 2a94ae0dc8b..747f2767633 100644
--- a/arch/powerpc/boot/dts/mpc8313erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8313erdb.dts
@@ -176,24 +176,28 @@
dma-channel@0 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8313-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -359,7 +363,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts
index f704513fb93..7449e54c1a9 100644
--- a/arch/powerpc/boot/dts/mpc8315erdb.dts
+++ b/arch/powerpc/boot/dts/mpc8315erdb.dts
@@ -144,24 +144,28 @@
dma-channel@0 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8315-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -314,7 +318,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts
index fbc930410ff..e4cc1768f24 100644
--- a/arch/powerpc/boot/dts/mpc832x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc832x_mds.dts
@@ -127,24 +127,28 @@
dma-channel@0 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -419,7 +423,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts
index b157d1885a2..226ff066652 100644
--- a/arch/powerpc/boot/dts/mpc832x_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts
@@ -105,24 +105,28 @@
dma-channel@0 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8323-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -327,7 +331,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
index 700e076ef3f..5cedf373a1d 100644
--- a/arch/powerpc/boot/dts/mpc8349emitx.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -106,24 +106,28 @@
dma-channel@0 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -250,7 +254,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
@@ -276,7 +281,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008600 0x100>;
+ reg = <0xe0008600 0x100 /* internal registers */
+ 0xe0008380 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
index cdd3063258e..81ae1d3e944 100644
--- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts
+++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts
@@ -104,24 +104,28 @@
dma-channel@0 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -224,7 +228,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008600 0x100>;
+ reg = <0xe0008600 0x100 /* internal registers */
+ 0xe0008380 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts
index 783241c0024..04bfde3ea60 100644
--- a/arch/powerpc/boot/dts/mpc834x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc834x_mds.dts
@@ -116,24 +116,28 @@
dma-channel@0 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -311,7 +315,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
@@ -372,7 +377,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008600 0x100>;
+ reg = <0xe0008600 0x100 /* internal registers */
+ 0xe0008380 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts
index a3b76a70995..66a12d2631f 100644
--- a/arch/powerpc/boot/dts/mpc836x_mds.dts
+++ b/arch/powerpc/boot/dts/mpc836x_mds.dts
@@ -52,9 +52,26 @@
reg = <0x00000000 0x10000000>;
};
- bcsr@f8000000 {
- device_type = "board-control";
- reg = <0xf8000000 0x8000>;
+ localbus@e0005000 {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ compatible = "fsl,mpc8360-localbus", "fsl,pq2pro-localbus",
+ "simple-bus";
+ reg = <0xe0005000 0xd8>;
+ ranges = <0 0 0xfe000000 0x02000000
+ 1 0 0xf8000000 0x00008000>;
+
+ flash@0,0 {
+ compatible = "cfi-flash";
+ reg = <0 0 0x2000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ bcsr@1,0 {
+ device_type = "board-control";
+ reg = <1 0 0x8000>;
+ };
};
soc8360@e0000000 {
@@ -131,24 +148,28 @@
dma-channel@0 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -405,7 +426,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts
index 89c9202f8bd..decadf3d9e9 100644
--- a/arch/powerpc/boot/dts/mpc836x_rdk.dts
+++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts
@@ -125,24 +125,28 @@
dma-channel@0 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8360-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -383,6 +387,18 @@
device-width = <1>;
};
+ upm@1,0 {
+ compatible = "fsl,upm-nand";
+ reg = <1 0 1>;
+ fsl,upm-addr-offset = <16>;
+ fsl,upm-cmd-offset = <8>;
+ gpios = <&qe_pio_e 18 0>;
+
+ flash {
+ compatible = "stm,nand512-a";
+ };
+ };
+
display@2,0 {
device_type = "display";
compatible = "fujitsu,MB86277", "fujitsu,mint";
@@ -405,7 +421,8 @@
#interrupt-cells = <1>;
device_type = "pci";
compatible = "fsl,mpc8360-pci", "fsl,mpc8349-pci";
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
ranges = <0x02000000 0 0x90000000 0x90000000 0 0x10000000
0x42000000 0 0x80000000 0x80000000 0 0x10000000
0x01000000 0 0xe0300000 0xe0300000 0 0x00100000>;
diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts
index 432782b6d20..0484561bd2c 100644
--- a/arch/powerpc/boot/dts/mpc8377_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8377_mds.dts
@@ -136,6 +136,13 @@
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
+
+ rtc@68 {
+ compatible = "dallas,ds1374";
+ reg = <0x68>;
+ interrupts = <19 0x8>;
+ interrupt-parent = <&ipic>;
+ };
};
i2c@3100 {
@@ -246,24 +253,28 @@
dma-channel@0 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <0x47 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <0x47 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <0x47 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <0x47 8>;
};
@@ -374,7 +385,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts
index ed137aa83d5..53191ba67aa 100644
--- a/arch/powerpc/boot/dts/mpc8377_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts
@@ -155,24 +155,28 @@
dma-channel@0 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8377-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -315,7 +319,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts
index ed32c8ddafe..67a08d2e2ff 100644
--- a/arch/powerpc/boot/dts/mpc8378_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8378_mds.dts
@@ -136,6 +136,13 @@
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
+
+ rtc@68 {
+ compatible = "dallas,ds1374";
+ reg = <0x68>;
+ interrupts = <19 0x8>;
+ interrupt-parent = <&ipic>;
+ };
};
i2c@3100 {
@@ -170,24 +177,28 @@
dma-channel@0 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -360,7 +371,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts
index 34a7f2f935e..4a09153d160 100644
--- a/arch/powerpc/boot/dts/mpc8378_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts
@@ -155,24 +155,28 @@
dma-channel@0 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8378-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -301,7 +305,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts
index f4db9ed4a30..323370a2b5f 100644
--- a/arch/powerpc/boot/dts/mpc8379_mds.dts
+++ b/arch/powerpc/boot/dts/mpc8379_mds.dts
@@ -136,6 +136,13 @@
interrupts = <14 0x8>;
interrupt-parent = <&ipic>;
dfsrr;
+
+ rtc@68 {
+ compatible = "dallas,ds1374";
+ reg = <0x68>;
+ interrupts = <19 0x8>;
+ interrupt-parent = <&ipic>;
+ };
};
i2c@3100 {
@@ -170,24 +177,28 @@
dma-channel@0 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -388,7 +399,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts
index e4d7030d50e..bbd884ac9dc 100644
--- a/arch/powerpc/boot/dts/mpc8379_rdb.dts
+++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts
@@ -155,24 +155,28 @@
dma-channel@0 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8379-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -329,7 +333,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts
index 1505d6855ef..93fdd99901b 100644
--- a/arch/powerpc/boot/dts/mpc8536ds.dts
+++ b/arch/powerpc/boot/dts/mpc8536ds.dts
@@ -91,6 +91,8 @@
rtc@68 {
compatible = "dallas,ds3232";
reg = <0x68>;
+ interrupts = <0 0x1>;
+ interrupt-parent = <&mpic>;
};
};
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
index 584a4f184eb..f724d72c7b9 100644
--- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts
+++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts
@@ -207,7 +207,7 @@
reg = <0xe4000 0x100>;
};
- i2s@16000 {
+ ssi@16000 {
compatible = "fsl,mpc8610-ssi";
cell-index = <0>;
reg = <0x16000 0x100>;
@@ -215,6 +215,8 @@
interrupts = <62 2>;
fsl,mode = "i2s-slave";
codec-handle = <&cs4270>;
+ fsl,playback-dma = <&dma00>;
+ fsl,capture-dma = <&dma01>;
};
ssi@16100 {
@@ -233,17 +235,17 @@
reg = <0x21300 0x4>; /* DMA general status register */
ranges = <0x0 0x21100 0x200>;
- dma-channel@0 {
+ dma00: dma-channel@0 {
compatible = "fsl,mpc8610-dma-channel",
- "fsl,eloplus-dma-channel";
+ "fsl,ssi-dma-channel";
cell-index = <0>;
reg = <0x0 0x80>;
interrupt-parent = <&mpic>;
interrupts = <20 2>;
};
- dma-channel@1 {
+ dma01: dma-channel@1 {
compatible = "fsl,mpc8610-dma-channel",
- "fsl,eloplus-dma-channel";
+ "fsl,ssi-dma-channel";
cell-index = <1>;
reg = <0x80 0x80>;
interrupt-parent = <&mpic>;
diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts
index 45f789b5670..0f941f310e4 100644
--- a/arch/powerpc/boot/dts/sbc8349.dts
+++ b/arch/powerpc/boot/dts/sbc8349.dts
@@ -107,24 +107,28 @@
dma-channel@0 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0 0x80>;
+ cell-index = <0>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@80 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x80 0x80>;
+ cell-index = <1>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@100 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x100 0x80>;
+ cell-index = <2>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
dma-channel@180 {
compatible = "fsl,mpc8349-dma-channel", "fsl,elo-dma-channel";
reg = <0x180 0x28>;
+ cell-index = <3>;
interrupt-parent = <&ipic>;
interrupts = <71 8>;
};
@@ -268,7 +272,8 @@
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
- reg = <0xe0008500 0x100>;
+ reg = <0xe0008500 0x100 /* internal registers */
+ 0xe0008300 0x8>; /* config space access registers */
compatible = "fsl,mpc8349-pci";
device_type = "pci";
};
diff --git a/arch/powerpc/boot/dts/sequoia.dts b/arch/powerpc/boot/dts/sequoia.dts
index 72d15f075d3..3b295e8df53 100644
--- a/arch/powerpc/boot/dts/sequoia.dts
+++ b/arch/powerpc/boot/dts/sequoia.dts
@@ -246,13 +246,22 @@
};
IIC0: i2c@ef600700 {
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "ibm,iic-440epx", "ibm,iic";
reg = <0xef600700 0x00000014>;
interrupt-parent = <&UIC0>;
interrupts = <0x2 0x4>;
+
+ hwmon@48 {
+ compatible = "adi,ad7414";
+ reg = <0x48>;
+ };
};
IIC1: i2c@ef600800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
compatible = "ibm,iic-440epx", "ibm,iic";
reg = <0xef600800 0x00000014>;
interrupt-parent = <&UIC0>;
diff --git a/arch/powerpc/boot/dts/yosemite.dts b/arch/powerpc/boot/dts/yosemite.dts
index e39422aa0d8..1fa3cb4c4eb 100644
--- a/arch/powerpc/boot/dts/yosemite.dts
+++ b/arch/powerpc/boot/dts/yosemite.dts
@@ -15,7 +15,7 @@
#address-cells = <2>;
#size-cells = <1>;
model = "amcc,yosemite";
- compatible = "amcc,yosemite","amcc,bamboo";
+ compatible = "amcc,yosemite";
dcr-parent = <&{/cpus/cpu@0}>;
aliases {
diff --git a/arch/powerpc/boot/elf_util.c b/arch/powerpc/boot/elf_util.c
index 7454aa4cc20..1567a0c0f05 100644
--- a/arch/powerpc/boot/elf_util.c
+++ b/arch/powerpc/boot/elf_util.c
@@ -27,7 +27,8 @@ int parse_elf64(void *hdr, struct elf_info *info)
elf64->e_ident[EI_MAG3] == ELFMAG3 &&
elf64->e_ident[EI_CLASS] == ELFCLASS64 &&
elf64->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf64->e_type == ET_EXEC &&
+ (elf64->e_type == ET_EXEC ||
+ elf64->e_type == ET_DYN) &&
elf64->e_machine == EM_PPC64))
return 0;
@@ -58,7 +59,8 @@ int parse_elf32(void *hdr, struct elf_info *info)
elf32->e_ident[EI_MAG3] == ELFMAG3 &&
elf32->e_ident[EI_CLASS] == ELFCLASS32 &&
elf32->e_ident[EI_DATA] == ELFDATA2MSB &&
- elf32->e_type == ET_EXEC &&
+ (elf32->e_type == ET_EXEC ||
+ elf32->e_type == ET_DYN) &&
elf32->e_machine == EM_PPC))
return 0;
diff --git a/arch/powerpc/boot/libfdt/Makefile.libfdt b/arch/powerpc/boot/libfdt/Makefile.libfdt
index 82f9c6a8287..6c42acfa21e 100644
--- a/arch/powerpc/boot/libfdt/Makefile.libfdt
+++ b/arch/powerpc/boot/libfdt/Makefile.libfdt
@@ -3,12 +3,6 @@
# This is not a complete Makefile of itself. Instead, it is designed to
# be easily embeddable into other systems of Makefiles.
#
-LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
LIBFDT_INCLUDES = fdt.h libfdt.h
-LIBFDT_EXTRA = libfdt_internal.h
-LIBFDT_LIB = libfdt/libfdt.a
-
+LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o)
-
-$(LIBFDT_objdir)/$(LIBFDT_LIB): $(addprefix $(LIBFDT_objdir)/,$(LIBFDT_OBJS))
-
diff --git a/arch/powerpc/boot/libfdt/fdt.c b/arch/powerpc/boot/libfdt/fdt.c
index 586a36136db..2acaec5923a 100644
--- a/arch/powerpc/boot/libfdt/fdt.c
+++ b/arch/powerpc/boot/libfdt/fdt.c
@@ -63,7 +63,7 @@ int fdt_check_header(const void *fdt)
return -FDT_ERR_BADVERSION;
if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
return -FDT_ERR_BADVERSION;
- } else if (fdt_magic(fdt) == SW_MAGIC) {
+ } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
/* Unfinished sequential-write blob */
if (fdt_size_dt_struct(fdt) == 0)
return -FDT_ERR_BADSTATE;
@@ -76,7 +76,7 @@ int fdt_check_header(const void *fdt)
const void *fdt_offset_ptr(const void *fdt, int offset, int len)
{
- const void *p;
+ const char *p;
if (fdt_version(fdt) >= 0x11)
if (((offset + len) < offset)
@@ -124,11 +124,59 @@ uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset)
}
if (nextoffset)
- *nextoffset = ALIGN(offset, FDT_TAGSIZE);
+ *nextoffset = FDT_TAGALIGN(offset);
return tag;
}
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+ if ((offset < 0) || (offset % FDT_TAGSIZE)
+ || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+ return -FDT_ERR_BADOFFSET;
+
+ return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+ int nextoffset = 0;
+ uint32_t tag;
+
+ if (offset >= 0)
+ if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+ return nextoffset;
+
+ do {
+ offset = nextoffset;
+ tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+ switch (tag) {
+ case FDT_PROP:
+ case FDT_NOP:
+ break;
+
+ case FDT_BEGIN_NODE:
+ if (depth)
+ (*depth)++;
+ break;
+
+ case FDT_END_NODE:
+ if (depth)
+ (*depth)--;
+ break;
+
+ case FDT_END:
+ return -FDT_ERR_NOTFOUND;
+
+ default:
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ } while (tag != FDT_BEGIN_NODE);
+
+ return offset;
+}
+
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
{
int len = strlen(s) + 1;
@@ -136,17 +184,14 @@ const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
const char *p;
for (p = strtab; p <= last; p++)
- if (memeq(p, s, len))
+ if (memcmp(p, s, len) == 0)
return p;
return NULL;
}
int fdt_move(const void *fdt, void *buf, int bufsize)
{
- int err = fdt_check_header(fdt);
-
- if (err)
- return err;
+ FDT_CHECK_HEADER(fdt);
if (fdt_totalsize(fdt) > bufsize)
return -FDT_ERR_NOSPACE;
diff --git a/arch/powerpc/boot/libfdt/fdt_ro.c b/arch/powerpc/boot/libfdt/fdt_ro.c
index 12a37d59f96..129b532bcc1 100644
--- a/arch/powerpc/boot/libfdt/fdt_ro.c
+++ b/arch/powerpc/boot/libfdt/fdt_ro.c
@@ -55,17 +55,10 @@
#include "libfdt_internal.h"
-#define CHECK_HEADER(fdt) \
- { \
- int err; \
- if ((err = fdt_check_header(fdt)) != 0) \
- return err; \
- }
-
-static int nodename_eq(const void *fdt, int offset,
- const char *s, int len)
+static int _fdt_nodename_eq(const void *fdt, int offset,
+ const char *s, int len)
{
- const char *p = fdt_offset_ptr(fdt, offset, len+1);
+ const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
if (! p)
/* short match */
@@ -84,12 +77,12 @@ static int nodename_eq(const void *fdt, int offset,
const char *fdt_string(const void *fdt, int stroffset)
{
- return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+ return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
}
int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
{
- CHECK_HEADER(fdt);
+ FDT_CHECK_HEADER(fdt);
*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
return 0;
@@ -104,50 +97,24 @@ int fdt_num_mem_rsv(const void *fdt)
return i;
}
-int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
const char *name, int namelen)
{
- int level = 0;
- uint32_t tag;
- int offset, nextoffset;
-
- CHECK_HEADER(fdt);
-
- tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- return -FDT_ERR_BADOFFSET;
-
- do {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
-
- switch (tag) {
- case FDT_END:
- return -FDT_ERR_TRUNCATED;
-
- case FDT_BEGIN_NODE:
- level++;
- if (level != 1)
- continue;
- if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
- /* Found it! */
- return offset;
- break;
-
- case FDT_END_NODE:
- level--;
- break;
+ int depth;
- case FDT_PROP:
- case FDT_NOP:
- break;
+ FDT_CHECK_HEADER(fdt);
- default:
- return -FDT_ERR_BADSTRUCTURE;
- }
- } while (level >= 0);
+ for (depth = 0;
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth < 0)
+ return -FDT_ERR_NOTFOUND;
+ else if ((depth == 1)
+ && _fdt_nodename_eq(fdt, offset, name, namelen))
+ return offset;
+ }
- return -FDT_ERR_NOTFOUND;
+ return offset; /* error */
}
int fdt_subnode_offset(const void *fdt, int parentoffset,
@@ -162,7 +129,7 @@ int fdt_path_offset(const void *fdt, const char *path)
const char *p = path;
int offset = 0;
- CHECK_HEADER(fdt);
+ FDT_CHECK_HEADER(fdt);
if (*path != '/')
return -FDT_ERR_BADPATH;
@@ -190,16 +157,12 @@ int fdt_path_offset(const void *fdt, const char *path)
const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
{
- const struct fdt_node_header *nh;
+ const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
int err;
- if ((err = fdt_check_header(fdt)) != 0)
- goto fail;
-
- err = -FDT_ERR_BADOFFSET;
- nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
- if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
- goto fail;
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
if (len)
*len = strlen(nh->name);
@@ -222,17 +185,11 @@ const struct fdt_property *fdt_get_property(const void *fdt,
int offset, nextoffset;
int err;
- if ((err = fdt_check_header(fdt)) != 0)
- goto fail;
-
- err = -FDT_ERR_BADOFFSET;
- if (nodeoffset % FDT_TAGSIZE)
- goto fail;
-
- tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- goto fail;
+ if (((err = fdt_check_header(fdt)) != 0)
+ || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+ goto fail;
+ nextoffset = err;
do {
offset = nextoffset;
@@ -253,7 +210,7 @@ const struct fdt_property *fdt_get_property(const void *fdt,
if (! prop)
goto fail;
namestroff = fdt32_to_cpu(prop->nameoff);
- if (streq(fdt_string(fdt, namestroff), name)) {
+ if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
/* Found it! */
int len = fdt32_to_cpu(prop->len);
prop = fdt_offset_ptr(fdt, offset,
@@ -307,115 +264,91 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
{
- uint32_t tag;
- int p = 0, overflow = 0;
- int offset, nextoffset, namelen;
+ int pdepth = 0, p = 0;
+ int offset, depth, namelen;
const char *name;
- CHECK_HEADER(fdt);
-
- tag = fdt_next_tag(fdt, 0, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- return -FDT_ERR_BADSTRUCTURE;
+ FDT_CHECK_HEADER(fdt);
if (buflen < 2)
return -FDT_ERR_NOSPACE;
- buf[0] = '/';
- p = 1;
- while (nextoffset <= nodeoffset) {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
- switch (tag) {
- case FDT_END:
- return -FDT_ERR_BADOFFSET;
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (pdepth < depth)
+ continue; /* overflowed buffer */
- case FDT_BEGIN_NODE:
- name = fdt_get_name(fdt, offset, &namelen);
- if (!name)
- return namelen;
- if (overflow || ((p + namelen + 1) > buflen)) {
- overflow++;
- break;
- }
+ while (pdepth > depth) {
+ do {
+ p--;
+ } while (buf[p-1] != '/');
+ pdepth--;
+ }
+
+ name = fdt_get_name(fdt, offset, &namelen);
+ if (!name)
+ return namelen;
+ if ((p + namelen + 1) <= buflen) {
memcpy(buf + p, name, namelen);
p += namelen;
buf[p++] = '/';
- break;
-
- case FDT_END_NODE:
- if (overflow) {
- overflow--;
- break;
- }
- do {
- p--;
- } while (buf[p-1] != '/');
- break;
+ pdepth++;
+ }
- case FDT_PROP:
- case FDT_NOP:
- break;
+ if (offset == nodeoffset) {
+ if (pdepth < (depth + 1))
+ return -FDT_ERR_NOSPACE;
- default:
- return -FDT_ERR_BADSTRUCTURE;
+ if (p > 1) /* special case so that root path is "/", not "" */
+ p--;
+ buf[p] = '\0';
+ return p;
}
}
- if (overflow)
- return -FDT_ERR_NOSPACE;
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
- if (p > 1) /* special case so that root path is "/", not "" */
- p--;
- buf[p] = '\0';
- return p;
+ return offset; /* error from fdt_next_node() */
}
int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
int supernodedepth, int *nodedepth)
{
- int level = -1;
- uint32_t tag;
- int offset, nextoffset = 0;
+ int offset, depth;
int supernodeoffset = -FDT_ERR_INTERNAL;
- CHECK_HEADER(fdt);
+ FDT_CHECK_HEADER(fdt);
if (supernodedepth < 0)
return -FDT_ERR_NOTFOUND;
- do {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
- switch (tag) {
- case FDT_END:
- return -FDT_ERR_BADOFFSET;
-
- case FDT_BEGIN_NODE:
- level++;
- if (level == supernodedepth)
- supernodeoffset = offset;
- break;
-
- case FDT_END_NODE:
- level--;
- break;
+ for (offset = 0, depth = 0;
+ (offset >= 0) && (offset <= nodeoffset);
+ offset = fdt_next_node(fdt, offset, &depth)) {
+ if (depth == supernodedepth)
+ supernodeoffset = offset;
- case FDT_PROP:
- case FDT_NOP:
- break;
+ if (offset == nodeoffset) {
+ if (nodedepth)
+ *nodedepth = depth;
- default:
- return -FDT_ERR_BADSTRUCTURE;
+ if (supernodedepth > depth)
+ return -FDT_ERR_NOTFOUND;
+ else
+ return supernodeoffset;
}
- } while (offset < nodeoffset);
+ }
- if (nodedepth)
- *nodedepth = level;
+ if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+ return -FDT_ERR_BADOFFSET;
+ else if (offset == -FDT_ERR_BADOFFSET)
+ return -FDT_ERR_BADSTRUCTURE;
- if (supernodedepth > level)
- return -FDT_ERR_NOTFOUND;
- return supernodeoffset;
+ return offset; /* error from fdt_next_node() */
}
int fdt_node_depth(const void *fdt, int nodeoffset)
@@ -443,51 +376,27 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
const char *propname,
const void *propval, int proplen)
{
- uint32_t tag;
- int offset, nextoffset;
+ int offset;
const void *val;
int len;
- CHECK_HEADER(fdt);
-
- if (startoffset >= 0) {
- tag = fdt_next_tag(fdt, startoffset, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- return -FDT_ERR_BADOFFSET;
- } else {
- nextoffset = 0;
- }
+ FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop(), then if that didn't
* find what we want, we scan over them again making our way
* to the next node. Still it's the easiest to implement
* approach; performance can come later. */
- do {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
-
- switch (tag) {
- case FDT_BEGIN_NODE:
- val = fdt_getprop(fdt, offset, propname, &len);
- if (val
- && (len == proplen)
- && (memcmp(val, propval, len) == 0))
- return offset;
- break;
-
- case FDT_PROP:
- case FDT_END:
- case FDT_END_NODE:
- case FDT_NOP:
- break;
-
- default:
- return -FDT_ERR_BADSTRUCTURE;
- }
- } while (tag != FDT_END);
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ val = fdt_getprop(fdt, offset, propname, &len);
+ if (val && (len == proplen)
+ && (memcmp(val, propval, len) == 0))
+ return offset;
+ }
- return -FDT_ERR_NOTFOUND;
+ return offset; /* error from fdt_next_node() */
}
int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
@@ -499,10 +408,10 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
&phandle, sizeof(phandle));
}
-int _stringlist_contains(const void *strlist, int listlen, const char *str)
+int _stringlist_contains(const char *strlist, int listlen, const char *str)
{
int len = strlen(str);
- const void *p;
+ const char *p;
while (listlen >= len) {
if (memcmp(str, strlist, len+1) == 0)
@@ -534,50 +443,24 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
const char *compatible)
{
- uint32_t tag;
- int offset, nextoffset;
- int err;
-
- CHECK_HEADER(fdt);
+ int offset, err;
- if (startoffset >= 0) {
- tag = fdt_next_tag(fdt, startoffset, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- return -FDT_ERR_BADOFFSET;
- } else {
- nextoffset = 0;
- }
+ FDT_CHECK_HEADER(fdt);
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible(), then if
* that didn't find what we want, we scan over them again
* making our way to the next node. Still it's the easiest to
* implement approach; performance can come later. */
- do {
- offset = nextoffset;
- tag = fdt_next_tag(fdt, offset, &nextoffset);
-
- switch (tag) {
- case FDT_BEGIN_NODE:
- err = fdt_node_check_compatible(fdt, offset,
- compatible);
- if ((err < 0)
- && (err != -FDT_ERR_NOTFOUND))
- return err;
- else if (err == 0)
- return offset;
- break;
-
- case FDT_PROP:
- case FDT_END:
- case FDT_END_NODE:
- case FDT_NOP:
- break;
-
- default:
- return -FDT_ERR_BADSTRUCTURE;
- }
- } while (tag != FDT_END);
+ for (offset = fdt_next_node(fdt, startoffset, NULL);
+ offset >= 0;
+ offset = fdt_next_node(fdt, offset, NULL)) {
+ err = fdt_node_check_compatible(fdt, offset, compatible);
+ if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+ return err;
+ else if (err == 0)
+ return offset;
+ }
- return -FDT_ERR_NOTFOUND;
+ return offset; /* error from fdt_next_node() */
}
diff --git a/arch/powerpc/boot/libfdt/fdt_rw.c b/arch/powerpc/boot/libfdt/fdt_rw.c
index 6673f8ec962..8e7ec4cb7bc 100644
--- a/arch/powerpc/boot/libfdt/fdt_rw.c
+++ b/arch/powerpc/boot/libfdt/fdt_rw.c
@@ -55,10 +55,10 @@
#include "libfdt_internal.h"
-static int _blocks_misordered(const void *fdt,
+static int _fdt_blocks_misordered(const void *fdt,
int mem_rsv_size, int struct_size)
{
- return (fdt_off_mem_rsvmap(fdt) < ALIGN(sizeof(struct fdt_header), 8))
+ return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
|| (fdt_off_dt_struct(fdt) <
(fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
|| (fdt_off_dt_strings(fdt) <
@@ -67,16 +67,14 @@ static int _blocks_misordered(const void *fdt,
(fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
}
-static int rw_check_header(void *fdt)
+static int _fdt_rw_check_header(void *fdt)
{
- int err;
+ FDT_CHECK_HEADER(fdt);
- if ((err = fdt_check_header(fdt)))
- return err;
if (fdt_version(fdt) < 17)
return -FDT_ERR_BADVERSION;
- if (_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
- fdt_size_dt_struct(fdt)))
+ if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+ fdt_size_dt_struct(fdt)))
return -FDT_ERR_BADLAYOUT;
if (fdt_version(fdt) > 17)
fdt_set_version(fdt, 17);
@@ -84,36 +82,37 @@ static int rw_check_header(void *fdt)
return 0;
}
-#define RW_CHECK_HEADER(fdt) \
+#define FDT_RW_CHECK_HEADER(fdt) \
{ \
int err; \
- if ((err = rw_check_header(fdt)) != 0) \
+ if ((err = _fdt_rw_check_header(fdt)) != 0) \
return err; \
}
-static inline int _blob_data_size(void *fdt)
+static inline int _fdt_data_size(void *fdt)
{
return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
}
-static int _blob_splice(void *fdt, void *p, int oldlen, int newlen)
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
{
- void *end = fdt + _blob_data_size(fdt);
+ char *p = splicepoint;
+ char *end = (char *)fdt + _fdt_data_size(fdt);
if (((p + oldlen) < p) || ((p + oldlen) > end))
return -FDT_ERR_BADOFFSET;
- if ((end - oldlen + newlen) > (fdt + fdt_totalsize(fdt)))
+ if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
return -FDT_ERR_NOSPACE;
memmove(p + newlen, p + oldlen, end - p - oldlen);
return 0;
}
-static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
- int oldn, int newn)
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+ int oldn, int newn)
{
int delta = (newn - oldn) * sizeof(*p);
int err;
- err = _blob_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+ err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
if (err)
return err;
fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
@@ -121,13 +120,13 @@ static int _blob_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
return 0;
}
-static int _blob_splice_struct(void *fdt, void *p,
- int oldlen, int newlen)
+static int _fdt_splice_struct(void *fdt, void *p,
+ int oldlen, int newlen)
{
int delta = newlen - oldlen;
int err;
- if ((err = _blob_splice(fdt, p, oldlen, newlen)))
+ if ((err = _fdt_splice(fdt, p, oldlen, newlen)))
return err;
fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
@@ -135,19 +134,20 @@ static int _blob_splice_struct(void *fdt, void *p,
return 0;
}
-static int _blob_splice_string(void *fdt, int newlen)
+static int _fdt_splice_string(void *fdt, int newlen)
{
- void *p = fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+ void *p = (char *)fdt
+ + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
int err;
- if ((err = _blob_splice(fdt, p, 0, newlen)))
+ if ((err = _fdt_splice(fdt, p, 0, newlen)))
return err;
fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
return 0;
}
-static int _find_add_string(void *fdt, const char *s)
+static int _fdt_find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
const char *p;
@@ -161,7 +161,7 @@ static int _find_add_string(void *fdt, const char *s)
return (p - strtab);
new = strtab + fdt_size_dt_strings(fdt);
- err = _blob_splice_string(fdt, len);
+ err = _fdt_splice_string(fdt, len);
if (err)
return err;
@@ -174,11 +174,10 @@ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
struct fdt_reserve_entry *re;
int err;
- if ((err = rw_check_header(fdt)))
- return err;
+ FDT_RW_CHECK_HEADER(fdt);
re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
- err = _blob_splice_mem_rsv(fdt, re, 0, 1);
+ err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
if (err)
return err;
@@ -192,19 +191,19 @@ int fdt_del_mem_rsv(void *fdt, int n)
struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
int err;
- if ((err = rw_check_header(fdt)))
- return err;
+ FDT_RW_CHECK_HEADER(fdt);
+
if (n >= fdt_num_mem_rsv(fdt))
return -FDT_ERR_NOTFOUND;
- err = _blob_splice_mem_rsv(fdt, re, 1, 0);
+ err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
if (err)
return err;
return 0;
}
-static int _resize_property(void *fdt, int nodeoffset, const char *name, int len,
- struct fdt_property **prop)
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
{
int oldlen;
int err;
@@ -213,36 +212,33 @@ static int _resize_property(void *fdt, int nodeoffset, const char *name, int len
if (! (*prop))
return oldlen;
- if ((err = _blob_splice_struct(fdt, (*prop)->data,
- ALIGN(oldlen, FDT_TAGSIZE),
- ALIGN(len, FDT_TAGSIZE))))
+ if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+ FDT_TAGALIGN(len))))
return err;
(*prop)->len = cpu_to_fdt32(len);
return 0;
}
-static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
- struct fdt_property **prop)
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+ int len, struct fdt_property **prop)
{
- uint32_t tag;
int proplen;
int nextoffset;
int namestroff;
int err;
- tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
- if (tag != FDT_BEGIN_NODE)
- return -FDT_ERR_BADOFFSET;
+ if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+ return nextoffset;
- namestroff = _find_add_string(fdt, name);
+ namestroff = _fdt_find_add_string(fdt, name);
if (namestroff < 0)
return namestroff;
*prop = _fdt_offset_ptr_w(fdt, nextoffset);
- proplen = sizeof(**prop) + ALIGN(len, FDT_TAGSIZE);
+ proplen = sizeof(**prop) + FDT_TAGALIGN(len);
- err = _blob_splice_struct(fdt, *prop, 0, proplen);
+ err = _fdt_splice_struct(fdt, *prop, 0, proplen);
if (err)
return err;
@@ -252,18 +248,40 @@ static int _add_property(void *fdt, int nodeoffset, const char *name, int len,
return 0;
}
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+ char *namep;
+ int oldlen, newlen;
+ int err;
+
+ FDT_RW_CHECK_HEADER(fdt);
+
+ namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+ if (!namep)
+ return oldlen;
+
+ newlen = strlen(name);
+
+ err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+ FDT_TAGALIGN(newlen+1));
+ if (err)
+ return err;
+
+ memcpy(namep, name, newlen+1);
+ return 0;
+}
+
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len)
{
struct fdt_property *prop;
int err;
- if ((err = rw_check_header(fdt)))
- return err;
+ FDT_RW_CHECK_HEADER(fdt);
- err = _resize_property(fdt, nodeoffset, name, len, &prop);
+ err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
if (err == -FDT_ERR_NOTFOUND)
- err = _add_property(fdt, nodeoffset, name, len, &prop);
+ err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
if (err)
return err;
@@ -276,14 +294,14 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name)
struct fdt_property *prop;
int len, proplen;
- RW_CHECK_HEADER(fdt);
+ FDT_RW_CHECK_HEADER(fdt);
prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
if (! prop)
return len;
- proplen = sizeof(*prop) + ALIGN(len, FDT_TAGSIZE);
- return _blob_splice_struct(fdt, prop, proplen, 0);
+ proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+ return _fdt_splice_struct(fdt, prop, proplen, 0);
}
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
@@ -296,7 +314,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
uint32_t tag;
uint32_t *endtag;
- RW_CHECK_HEADER(fdt);
+ FDT_RW_CHECK_HEADER(fdt);
offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
if (offset >= 0)
@@ -309,19 +327,19 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
do {
offset = nextoffset;
tag = fdt_next_tag(fdt, offset, &nextoffset);
- } while (tag == FDT_PROP);
+ } while ((tag == FDT_PROP) || (tag == FDT_NOP));
nh = _fdt_offset_ptr_w(fdt, offset);
- nodelen = sizeof(*nh) + ALIGN(namelen+1, FDT_TAGSIZE) + FDT_TAGSIZE;
+ nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
- err = _blob_splice_struct(fdt, nh, 0, nodelen);
+ err = _fdt_splice_struct(fdt, nh, 0, nodelen);
if (err)
return err;
nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
- memset(nh->name, 0, ALIGN(namelen+1, FDT_TAGSIZE));
+ memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
memcpy(nh->name, name, namelen);
- endtag = (uint32_t *)((void *)nh + nodelen - FDT_TAGSIZE);
+ endtag = (uint32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
*endtag = cpu_to_fdt32(FDT_END_NODE);
return offset;
@@ -336,36 +354,36 @@ int fdt_del_node(void *fdt, int nodeoffset)
{
int endoffset;
- RW_CHECK_HEADER(fdt);
+ FDT_RW_CHECK_HEADER(fdt);
endoffset = _fdt_node_end_offset(fdt, nodeoffset);
if (endoffset < 0)
return endoffset;
- return _blob_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
- endoffset - nodeoffset, 0);
+ return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+ endoffset - nodeoffset, 0);
}
-static void _packblocks(const void *fdt, void *buf,
- int mem_rsv_size, int struct_size)
+static void _fdt_packblocks(const char *old, char *new,
+ int mem_rsv_size, int struct_size)
{
int mem_rsv_off, struct_off, strings_off;
- mem_rsv_off = ALIGN(sizeof(struct fdt_header), 8);
+ mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
struct_off = mem_rsv_off + mem_rsv_size;
strings_off = struct_off + struct_size;
- memmove(buf + mem_rsv_off, fdt + fdt_off_mem_rsvmap(fdt), mem_rsv_size);
- fdt_set_off_mem_rsvmap(buf, mem_rsv_off);
+ memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+ fdt_set_off_mem_rsvmap(new, mem_rsv_off);
- memmove(buf + struct_off, fdt + fdt_off_dt_struct(fdt), struct_size);
- fdt_set_off_dt_struct(buf, struct_off);
- fdt_set_size_dt_struct(buf, struct_size);
+ memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+ fdt_set_off_dt_struct(new, struct_off);
+ fdt_set_size_dt_struct(new, struct_size);
- memmove(buf + strings_off, fdt + fdt_off_dt_strings(fdt),
- fdt_size_dt_strings(fdt));
- fdt_set_off_dt_strings(buf, strings_off);
- fdt_set_size_dt_strings(buf, fdt_size_dt_strings(fdt));
+ memmove(new + strings_off, old + fdt_off_dt_strings(old),
+ fdt_size_dt_strings(old));
+ fdt_set_off_dt_strings(new, strings_off);
+ fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
}
int fdt_open_into(const void *fdt, void *buf, int bufsize)
@@ -373,11 +391,11 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
int err;
int mem_rsv_size, struct_size;
int newsize;
- void *tmp;
+ const char *fdtstart = fdt;
+ const char *fdtend = fdtstart + fdt_totalsize(fdt);
+ char *tmp;
- err = fdt_check_header(fdt);
- if (err)
- return err;
+ FDT_CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
@@ -390,7 +408,7 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
;
}
- if (!_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+ if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
/* no further work necessary */
err = fdt_move(fdt, buf, bufsize);
if (err)
@@ -402,22 +420,23 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
}
/* Need to reorder */
- newsize = ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+ struct_size + fdt_size_dt_strings(fdt);
if (bufsize < newsize)
return -FDT_ERR_NOSPACE;
- if (((buf + newsize) <= fdt)
- || (buf >= (fdt + fdt_totalsize(fdt)))) {
- tmp = buf;
- } else {
- tmp = (void *)fdt + fdt_totalsize(fdt);
- if ((tmp + newsize) > (buf + bufsize))
+ /* First attempt to build converted tree at beginning of buffer */
+ tmp = buf;
+ /* But if that overlaps with the old tree... */
+ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+ /* Try right after the old tree instead */
+ tmp = (char *)(uintptr_t)fdtend;
+ if ((tmp + newsize) > ((char *)buf + bufsize))
return -FDT_ERR_NOSPACE;
}
- _packblocks(fdt, tmp, mem_rsv_size, struct_size);
+ _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
memmove(buf, tmp, newsize);
fdt_set_magic(buf, FDT_MAGIC);
@@ -432,16 +451,13 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize)
int fdt_pack(void *fdt)
{
int mem_rsv_size;
- int err;
- err = rw_check_header(fdt);
- if (err)
- return err;
+ FDT_RW_CHECK_HEADER(fdt);
mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
* sizeof(struct fdt_reserve_entry);
- _packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
- fdt_set_totalsize(fdt, _blob_data_size(fdt));
+ _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+ fdt_set_totalsize(fdt, _fdt_data_size(fdt));
return 0;
}
diff --git a/arch/powerpc/boot/libfdt/fdt_strerror.c b/arch/powerpc/boot/libfdt/fdt_strerror.c
index f9d32ef5360..e6c3ceee8c5 100644
--- a/arch/powerpc/boot/libfdt/fdt_strerror.c
+++ b/arch/powerpc/boot/libfdt/fdt_strerror.c
@@ -55,29 +55,29 @@
#include "libfdt_internal.h"
-struct errtabent {
+struct fdt_errtabent {
const char *str;
};
-#define ERRTABENT(val) \
+#define FDT_ERRTABENT(val) \
[(val)] = { .str = #val, }
-static struct errtabent errtable[] = {
- ERRTABENT(FDT_ERR_NOTFOUND),
- ERRTABENT(FDT_ERR_EXISTS),
- ERRTABENT(FDT_ERR_NOSPACE),
+static struct fdt_errtabent fdt_errtable[] = {
+ FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+ FDT_ERRTABENT(FDT_ERR_EXISTS),
+ FDT_ERRTABENT(FDT_ERR_NOSPACE),
- ERRTABENT(FDT_ERR_BADOFFSET),
- ERRTABENT(FDT_ERR_BADPATH),
- ERRTABENT(FDT_ERR_BADSTATE),
+ FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+ FDT_ERRTABENT(FDT_ERR_BADPATH),
+ FDT_ERRTABENT(FDT_ERR_BADSTATE),
- ERRTABENT(FDT_ERR_TRUNCATED),
- ERRTABENT(FDT_ERR_BADMAGIC),
- ERRTABENT(FDT_ERR_BADVERSION),
- ERRTABENT(FDT_ERR_BADSTRUCTURE),
- ERRTABENT(FDT_ERR_BADLAYOUT),
+ FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+ FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+ FDT_ERRTABENT(FDT_ERR_BADVERSION),
+ FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+ FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
};
-#define ERRTABSIZE (sizeof(errtable) / sizeof(errtable[0]))
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
const char *fdt_strerror(int errval)
{
@@ -85,8 +85,8 @@ const char *fdt_strerror(int errval)
return "<valid offset/length>";
else if (errval == 0)
return "<no error>";
- else if (errval > -ERRTABSIZE) {
- const char *s = errtable[-errval].str;
+ else if (errval > -FDT_ERRTABSIZE) {
+ const char *s = fdt_errtable[-errval].str;
if (s)
return s;
diff --git a/arch/powerpc/boot/libfdt/fdt_sw.c b/arch/powerpc/boot/libfdt/fdt_sw.c
index dda2de34b2e..698329e0cca 100644
--- a/arch/powerpc/boot/libfdt/fdt_sw.c
+++ b/arch/powerpc/boot/libfdt/fdt_sw.c
@@ -55,14 +55,22 @@
#include "libfdt_internal.h"
-static int check_header_sw(void *fdt)
+static int _fdt_sw_check_header(void *fdt)
{
- if (fdt_magic(fdt) != SW_MAGIC)
+ if (fdt_magic(fdt) != FDT_SW_MAGIC)
return -FDT_ERR_BADMAGIC;
+ /* FIXME: should check more details about the header state */
return 0;
}
-static void *grab_space(void *fdt, int len)
+#define FDT_SW_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = _fdt_sw_check_header(fdt)) != 0) \
+ return err; \
+ }
+
+static void *_fdt_grab_space(void *fdt, int len)
{
int offset = fdt_size_dt_struct(fdt);
int spaceleft;
@@ -86,13 +94,13 @@ int fdt_create(void *buf, int bufsize)
memset(buf, 0, bufsize);
- fdt_set_magic(fdt, SW_MAGIC);
+ fdt_set_magic(fdt, FDT_SW_MAGIC);
fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
fdt_set_totalsize(fdt, bufsize);
- fdt_set_off_mem_rsvmap(fdt, ALIGN(sizeof(struct fdt_header),
- sizeof(struct fdt_reserve_entry)));
+ fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+ sizeof(struct fdt_reserve_entry)));
fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
fdt_set_off_dt_strings(fdt, bufsize);
@@ -102,11 +110,10 @@ int fdt_create(void *buf, int bufsize)
int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
{
struct fdt_reserve_entry *re;
- int err = check_header_sw(fdt);
int offset;
- if (err)
- return err;
+ FDT_SW_CHECK_HEADER(fdt);
+
if (fdt_size_dt_struct(fdt))
return -FDT_ERR_BADSTATE;
@@ -114,7 +121,7 @@ int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
return -FDT_ERR_NOSPACE;
- re = (struct fdt_reserve_entry *)(fdt + offset);
+ re = (struct fdt_reserve_entry *)((char *)fdt + offset);
re->address = cpu_to_fdt64(addr);
re->size = cpu_to_fdt64(size);
@@ -131,13 +138,11 @@ int fdt_finish_reservemap(void *fdt)
int fdt_begin_node(void *fdt, const char *name)
{
struct fdt_node_header *nh;
- int err = check_header_sw(fdt);
int namelen = strlen(name) + 1;
- if (err)
- return err;
+ FDT_SW_CHECK_HEADER(fdt);
- nh = grab_space(fdt, sizeof(*nh) + ALIGN(namelen, FDT_TAGSIZE));
+ nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
if (! nh)
return -FDT_ERR_NOSPACE;
@@ -149,12 +154,10 @@ int fdt_begin_node(void *fdt, const char *name)
int fdt_end_node(void *fdt)
{
uint32_t *en;
- int err = check_header_sw(fdt);
- if (err)
- return err;
+ FDT_SW_CHECK_HEADER(fdt);
- en = grab_space(fdt, FDT_TAGSIZE);
+ en = _fdt_grab_space(fdt, FDT_TAGSIZE);
if (! en)
return -FDT_ERR_NOSPACE;
@@ -162,7 +165,7 @@ int fdt_end_node(void *fdt)
return 0;
}
-static int find_add_string(void *fdt, const char *s)
+static int _fdt_find_add_string(void *fdt, const char *s)
{
char *strtab = (char *)fdt + fdt_totalsize(fdt);
const char *p;
@@ -188,17 +191,15 @@ static int find_add_string(void *fdt, const char *s)
int fdt_property(void *fdt, const char *name, const void *val, int len)
{
struct fdt_property *prop;
- int err = check_header_sw(fdt);
int nameoff;
- if (err)
- return err;
+ FDT_SW_CHECK_HEADER(fdt);
- nameoff = find_add_string(fdt, name);
+ nameoff = _fdt_find_add_string(fdt, name);
if (nameoff == 0)
return -FDT_ERR_NOSPACE;
- prop = grab_space(fdt, sizeof(*prop) + ALIGN(len, FDT_TAGSIZE));
+ prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
if (! prop)
return -FDT_ERR_NOSPACE;
@@ -211,18 +212,16 @@ int fdt_property(void *fdt, const char *name, const void *val, int len)
int fdt_finish(void *fdt)
{
- int err = check_header_sw(fdt);
char *p = (char *)fdt;
uint32_t *end;
int oldstroffset, newstroffset;
uint32_t tag;
int offset, nextoffset;
- if (err)
- return err;
+ FDT_SW_CHECK_HEADER(fdt);
/* Add terminator */
- end = grab_space(fdt, sizeof(*end));
+ end = _fdt_grab_space(fdt, sizeof(*end));
if (! end)
return -FDT_ERR_NOSPACE;
*end = cpu_to_fdt32(FDT_END);
diff --git a/arch/powerpc/boot/libfdt/fdt_wip.c b/arch/powerpc/boot/libfdt/fdt_wip.c
index 88e24b8318f..a4652c6e787 100644
--- a/arch/powerpc/boot/libfdt/fdt_wip.c
+++ b/arch/powerpc/boot/libfdt/fdt_wip.c
@@ -72,11 +72,11 @@ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
return 0;
}
-static void nop_region(void *start, int len)
+static void _fdt_nop_region(void *start, int len)
{
uint32_t *p;
- for (p = start; (void *)p < (start + len); p++)
+ for (p = start; (char *)p < ((char *)start + len); p++)
*p = cpu_to_fdt32(FDT_NOP);
}
@@ -89,7 +89,7 @@ int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
if (! prop)
return len;
- nop_region(prop, len + sizeof(*prop));
+ _fdt_nop_region(prop, len + sizeof(*prop));
return 0;
}
@@ -139,6 +139,7 @@ int fdt_nop_node(void *fdt, int nodeoffset)
if (endoffset < 0)
return endoffset;
- nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset);
+ _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+ endoffset - nodeoffset);
return 0;
}
diff --git a/arch/powerpc/boot/libfdt/libfdt.h b/arch/powerpc/boot/libfdt/libfdt.h
index 6b2fb92ea35..ce80e4fb41b 100644
--- a/arch/powerpc/boot/libfdt/libfdt.h
+++ b/arch/powerpc/boot/libfdt/libfdt.h
@@ -125,12 +125,18 @@
const void *fdt_offset_ptr(const void *fdt, int offset, int checklen);
static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
{
- return (void *)fdt_offset_ptr(fdt, offset, checklen);
+ return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
}
uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
/**********************************************************************/
+/* Traversal functions */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**********************************************************************/
/* General functions */
/**********************************************************************/
@@ -207,7 +213,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
/**********************************************************************/
/**
- * fdt_string - retreive a string from the strings block of a device tree
+ * fdt_string - retrieve a string from the strings block of a device tree
* @fdt: pointer to the device tree blob
* @stroffset: offset of the string within the strings block (native endian)
*
@@ -221,7 +227,7 @@ int fdt_move(const void *fdt, void *buf, int bufsize);
const char *fdt_string(const void *fdt, int stroffset);
/**
- * fdt_num_mem_rsv - retreive the number of memory reserve map entries
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
* @fdt: pointer to the device tree blob
*
* Returns the number of entries in the device tree blob's memory
@@ -234,7 +240,7 @@ const char *fdt_string(const void *fdt, int stroffset);
int fdt_num_mem_rsv(const void *fdt);
/**
- * fdt_get_mem_rsv - retreive one memory reserve map entry
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
* @fdt: pointer to the device tree blob
* @address, @size: pointers to 64-bit variables
*
@@ -314,7 +320,7 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
int fdt_path_offset(const void *fdt, const char *path);
/**
- * fdt_get_name - retreive the name of a given node
+ * fdt_get_name - retrieve the name of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of the starting node
* @lenp: pointer to an integer variable (will be overwritten) or NULL
@@ -346,7 +352,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
* fdt_get_property() retrieves a pointer to the fdt_property
* structure within the device tree blob corresponding to the property
* named 'name' of the node at offset nodeoffset. If lenp is
- * non-NULL, the length of the property value also returned, in the
+ * non-NULL, the length of the property value is also returned, in the
* integer pointed to by lenp.
*
* returns:
@@ -369,8 +375,8 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
const char *name,
int *lenp)
{
- return (struct fdt_property *)fdt_get_property(fdt, nodeoffset,
- name, lenp);
+ return (struct fdt_property *)(uintptr_t)
+ fdt_get_property(fdt, nodeoffset, name, lenp);
}
/**
@@ -383,7 +389,7 @@ static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
* fdt_getprop() retrieves a pointer to the value of the property
* named 'name' of the node at offset nodeoffset (this will be a
* pointer to within the device blob itself, not a copy of the value).
- * If lenp is non-NULL, the length of the property value also
+ * If lenp is non-NULL, the length of the property value is also
* returned, in the integer pointed to by lenp.
*
* returns:
@@ -405,11 +411,11 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
const char *name, int *lenp)
{
- return (void *)fdt_getprop(fdt, nodeoffset, name, lenp);
+ return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
}
/**
- * fdt_get_phandle - retreive the phandle of a given node
+ * fdt_get_phandle - retrieve the phandle of a given node
* @fdt: pointer to the device tree blob
* @nodeoffset: structure block offset of the node
*
@@ -417,7 +423,7 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
* structure block offset nodeoffset.
*
* returns:
- * the phandle of the node at nodeoffset, on succes (!= 0, != -1)
+ * the phandle of the node at nodeoffset, on success (!= 0, != -1)
* 0, if the node has no phandle, or another error occurs
*/
uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
@@ -516,7 +522,7 @@ int fdt_node_depth(const void *fdt, int nodeoffset);
* structure from the start to nodeoffset, *twice*.
*
* returns:
- * stucture block offset of the parent of the node at nodeoffset
+ * structure block offset of the parent of the node at nodeoffset
* (>=0), on success
* -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
* -FDT_ERR_BADMAGIC,
@@ -573,7 +579,7 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
* @fdt: pointer to the device tree blob
* @phandle: phandle value
*
- * fdt_node_offset_by_prop_value() returns the offset of the node
+ * fdt_node_offset_by_phandle() returns the offset of the node
* which has the given phandle value. If there is more than one node
* in the tree with the given phandle (an invalid tree), results are
* undefined.
@@ -655,8 +661,65 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
/* Write-in-place functions */
/**********************************************************************/
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len. This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: cell (32-bit integer) value to replace the property with
+ *
+ * fdt_setprop_inplace_cell() replaces the value of a given property
+ * with the 32-bit integer cell value in val, converting val to
+ * big-endian if necessary. This function cannot change the size of a
+ * property, and so will only work if the property already exists and
+ * has length 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
const char *name, uint32_t val)
{
@@ -664,7 +727,54 @@ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
return fdt_setprop_inplace(fdt, nodeoffset, name, &val, sizeof(val));
}
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_nop_node(void *fdt, int nodeoffset);
/**********************************************************************/
@@ -693,23 +803,268 @@ int fdt_finish(void *fdt);
int fdt_open_into(const void *fdt, void *buf, int bufsize);
int fdt_pack(void *fdt);
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new reservation entry
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ * are less than n+1 reserve map entries)
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_del_mem_rsv(void *fdt, int n);
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string. NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ * to contain the new name
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_setprop(void *fdt, int nodeoffset, const char *name,
const void *val, int len);
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_cell() sets the value of the named property in the
+ * given node to the given cell value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
uint32_t val)
{
val = cpu_to_fdt32(val);
return fdt_setprop(fdt, nodeoffset, name, &val, sizeof(val));
}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ * contain the new property value
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
#define fdt_setprop_string(fdt, nodeoffset, name, str) \
fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_NOTFOUND, node does not have the named property
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node. This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
int fdt_add_subnode_namelen(void *fdt, int parentoffset,
const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ * structure block offset of the created nodeequested subnode (>=0), on success
+ * -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ * the given name
+ * -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ * blob to contain the new node
+ * -FDT_ERR_NOSPACE
+ * -FDT_ERR_BADLAYOUT
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings.
+ */
int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ * 0, on success
+ * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ * -FDT_ERR_BADLAYOUT,
+ * -FDT_ERR_BADMAGIC,
+ * -FDT_ERR_BADVERSION,
+ * -FDT_ERR_BADSTATE,
+ * -FDT_ERR_BADSTRUCTURE,
+ * -FDT_ERR_TRUNCATED, standard meanings
+ */
int fdt_del_node(void *fdt, int nodeoffset);
/**********************************************************************/
diff --git a/arch/powerpc/boot/libfdt/libfdt_internal.h b/arch/powerpc/boot/libfdt/libfdt_internal.h
index 1e60936beb5..46eb93e4af5 100644
--- a/arch/powerpc/boot/libfdt/libfdt_internal.h
+++ b/arch/powerpc/boot/libfdt/libfdt_internal.h
@@ -52,38 +52,44 @@
*/
#include <fdt.h>
-#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
-#define PALIGN(p, a) ((void *)ALIGN((unsigned long)(p), (a)))
+#define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE))
-#define memeq(p, q, n) (memcmp((p), (q), (n)) == 0)
-#define streq(p, q) (strcmp((p), (q)) == 0)
+#define FDT_CHECK_HEADER(fdt) \
+ { \
+ int err; \
+ if ((err = fdt_check_header(fdt)) != 0) \
+ return err; \
+ }
uint32_t _fdt_next_tag(const void *fdt, int startoffset, int *nextoffset);
+int _fdt_check_node_offset(const void *fdt, int offset);
const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
int _fdt_node_end_offset(void *fdt, int nodeoffset);
static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
{
- return fdt + fdt_off_dt_struct(fdt) + offset;
+ return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
}
static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
{
- return (void *)_fdt_offset_ptr(fdt, offset);
+ return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
}
static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
{
const struct fdt_reserve_entry *rsv_table =
- fdt + fdt_off_mem_rsvmap(fdt);
+ (const struct fdt_reserve_entry *)
+ ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
return rsv_table + n;
}
static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
{
- return (void *)_fdt_mem_rsv(fdt, n);
+ return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
}
-#define SW_MAGIC (~FDT_MAGIC)
+#define FDT_SW_MAGIC (~FDT_MAGIC)
#endif /* _LIBFDT_INTERNAL_H */
diff --git a/arch/powerpc/boot/libfdt_env.h b/arch/powerpc/boot/libfdt_env.h
index a4b0fc959ec..c89fdb1b80e 100644
--- a/arch/powerpc/boot/libfdt_env.h
+++ b/arch/powerpc/boot/libfdt_env.h
@@ -6,6 +6,7 @@
typedef u32 uint32_t;
typedef u64 uint64_t;
+typedef unsigned long uintptr_t;
#define fdt16_to_cpu(x) (x)
#define cpu_to_fdt16(x) (x)
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
index 965c237c122..ee0dc41d7c5 100755
--- a/arch/powerpc/boot/wrapper
+++ b/arch/powerpc/boot/wrapper
@@ -307,7 +307,9 @@ fi
# post-processing needed for some platforms
case "$platform" in
pseries|chrp)
- $objbin/addnote "$ofile"
+ ${CROSS}objcopy -O binary -j .fakeelf "$kernel" "$ofile".rpanote
+ $objbin/addnote "$ofile" "$ofile".rpanote
+ rm -r "$ofile".rpanote
;;
coff)
${CROSS}objcopy -O aixcoff-rs6000 --set-start "$entry" "$ofile"
diff --git a/arch/powerpc/configs/44x/arches_defconfig b/arch/powerpc/configs/44x/arches_defconfig
new file mode 100644
index 00000000000..70f46078eb6
--- /dev/null
+++ b/arch/powerpc/configs/44x/arches_defconfig
@@ -0,0 +1,767 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Wed Oct 1 15:54:57 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+CONFIG_44x=y
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_4xx=y
+CONFIG_BOOKE=y
+CONFIG_PTE_64BIT=y
+CONFIG_PHYS_64BIT=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+CONFIG_PPC_DCR_NATIVE=y
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_PPC_DCR=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=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_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+# CONFIG_USE_GENERIC_SMP_HELPERS is not set
+# CONFIG_HAVE_CLK is not set
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY 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_CLASSIC_RCU=y
+CONFIG_PPC4xx_PCI_EXPRESS=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_BAMBOO is not set
+# CONFIG_EBONY is not set
+# CONFIG_SAM440EP is not set
+# CONFIG_SEQUOIA is not set
+# CONFIG_TAISHAN is not set
+# CONFIG_KATMAI is not set
+# CONFIG_RAINIER is not set
+# CONFIG_WARP is not set
+CONFIG_ARCHES=y
+# CONFIG_CANYONLANDS is not set
+# CONFIG_GLACIER is not set
+# CONFIG_YOSEMITE is not set
+# CONFIG_XILINX_VIRTEX440_GENERIC_BOARD is not set
+CONFIG_PPC44x_SIMPLE=y
+CONFIG_460EX=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_RESOURCES_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE=""
+CONFIG_EXTRA_TARGETS=""
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_4xx_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+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 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 is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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 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=35000
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_XILINX_SYSACE is not set
+# CONFIG_BLK_DEV_HD is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_IBM_NEW_EMAC=y
+CONFIG_IBM_NEW_EMAC_RXB=256
+CONFIG_IBM_NEW_EMAC_TXB=256
+CONFIG_IBM_NEW_EMAC_POLL_WEIGHT=32
+CONFIG_IBM_NEW_EMAC_RX_COPY_THRESHOLD=256
+CONFIG_IBM_NEW_EMAC_RX_SKB_HEADROOM=0
+# CONFIG_IBM_NEW_EMAC_DEBUG is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+CONFIG_IBM_NEW_EMAC_TAH=y
+CONFIG_IBM_NEW_EMAC_EMAC4=y
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# 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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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_EXT4DEV_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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=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
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_CRYPTO is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/83xx/asp8347_defconfig b/arch/powerpc/configs/83xx/asp8347_defconfig
index 5e6780a088c..0b1fa20f745 100644
--- a/arch/powerpc/configs/83xx/asp8347_defconfig
+++ b/arch/powerpc/configs/83xx/asp8347_defconfig
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
index 2028337868b..b7eae2bdf19 100644
--- a/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8313_rdb_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
index dd80eb0a87a..b0a27a67d8c 100644
--- a/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc8315_rdb_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
index bdf50c8a17e..ad825bcddd1 100644
--- a/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_mds_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
index 4eef8c95480..38267501f44 100644
--- a/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc832x_rdb_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
index 8d651393185..90aab340e7f 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itx_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
index a8afa39d6f7..7458a242d25 100644
--- a/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
index 24c320a3667..1a92798938c 100644
--- a/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc834x_mds_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
index e029e9e1462..03d8cede027 100644
--- a/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_mds_defconfig
@@ -163,11 +163,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
@@ -383,7 +383,84 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
# CONFIG_CONNECTOR is not set
-# CONFIG_MTD is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=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
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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 is not set
+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=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# 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
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
CONFIG_OF_DEVICE=y
CONFIG_OF_I2C=y
# CONFIG_PARPORT is not set
diff --git a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
index 7d674be702f..cdf84177370 100644
--- a/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
+++ b/arch/powerpc/configs/83xx/mpc836x_rdk_defconfig
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
index de472022aa8..97e02d7a5b0 100644
--- a/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_mds_defconfig
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
index e8d2d691d26..5ac33054ce2 100644
--- a/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
+++ b/arch/powerpc/configs/83xx/mpc837x_rdb_defconfig
@@ -164,11 +164,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/83xx/sbc834x_defconfig b/arch/powerpc/configs/83xx/sbc834x_defconfig
index 9245a67da20..c359cc2a380 100644
--- a/arch/powerpc/configs/83xx/sbc834x_defconfig
+++ b/arch/powerpc/configs/83xx/sbc834x_defconfig
@@ -162,11 +162,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
new file mode 100644
index 00000000000..312d7afbbe4
--- /dev/null
+++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig
@@ -0,0 +1,1657 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc5
+# Wed Jun 11 12:06:53 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=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_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_MPC8641_HPCN is not set
+# CONFIG_SBC8641D is not set
+# CONFIG_MPC8610_HPCD is not set
+CONFIG_GEF_SBC610=y
+CONFIG_MPC8641=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_FSL_ULI1575 is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_IRQ_ALL_CPUS=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+CONFIG_PCI_DEBUG=y
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+CONFIG_NETFILTER_XTABLES=m
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_PHYSDEV is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+# CONFIG_IP_NF_MATCH_AH is not set
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+# CONFIG_IP6_NF_MATCH_AH is not set
+# CONFIG_IP6_NF_MATCH_MH is not set
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+# CONFIG_IP6_NF_TARGET_REJECT is not set
+CONFIG_IP6_NF_MANGLE=m
+# CONFIG_IP6_NF_TARGET_HL is not set
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_TIPC=m
+# CONFIG_TIPC_ADVANCED is not set
+# CONFIG_TIPC_DEBUG is not set
+CONFIG_ATM=m
+CONFIG_ATM_CLIP=m
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+# CONFIG_ATM_BR2684_IPFILTER is not set
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# 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_ECONET is not set
+CONFIG_WAN_ROUTER=m
+CONFIG_NET_SCHED=y
+
+#
+# Queueing/Scheduling
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_ATM=m
+CONFIG_NET_SCH_PRIO=m
+# CONFIG_NET_SCH_RR is not set
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+# CONFIG_NET_CLS_BASIC is not set
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_FLOW is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_SCH_FIFO=y
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=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
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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 is not set
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_LE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+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=y
+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=y
+# 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# 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
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+# 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 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_E1000E_ENABLED is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_GFAR_NAPI is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_ATM_DRIVERS=y
+# CONFIG_ATM_DUMMY is not set
+# CONFIG_ATM_TCP is not set
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+# CONFIG_ATM_FORE200E_MAYBE is not set
+# CONFIG_ATM_HE is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+# CONFIG_PPP_MPPE is not set
+CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
+# CONFIG_PPPOL2TP is not set
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+CONFIG_NETPOLL_TRAP=y
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# 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_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_TABLET 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=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# 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_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIMTEC is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_TINY_USB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
+# CONFIG_I2C_PCA_PLATFORM is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+CONFIG_DS1682=y
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+CONFIG_SENSORS_LM90=y
+CONFIG_SENSORS_LM92=y
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 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_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT 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
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+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
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# 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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+# CONFIG_USB_MON is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_ATM is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=m
+CONFIG_RTC_CLASS=m
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+# CONFIG_RTC_INTF_PROC is not set
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_BIND34 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=m
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+CONFIG_DEBUGGER=y
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+CONFIG_SECURITY_NETWORK=y
+# CONFIG_SECURITY_NETWORK_XFRM is not set
+CONFIG_SECURITY_CAPABILITIES=y
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/mpc8610_hpcd_defconfig b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
index 1a9990731eb..c98c6ee4449 100644
--- a/arch/powerpc/configs/mpc8610_hpcd_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig
@@ -165,11 +165,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/mpc8641_hpcn_defconfig b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
index ea09be31b6e..444ddf98436 100644
--- a/arch/powerpc/configs/mpc8641_hpcn_defconfig
+++ b/arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig
@@ -167,11 +167,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/sbc8641d_defconfig b/arch/powerpc/configs/86xx/sbc8641d_defconfig
index f545421f985..d900f8f376c 100644
--- a/arch/powerpc/configs/sbc8641d_defconfig
+++ b/arch/powerpc/configs/86xx/sbc8641d_defconfig
@@ -166,11 +166,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/ep8248e_defconfig b/arch/powerpc/configs/ep8248e_defconfig
index ef0c6e80050..cd691f77081 100644
--- a/arch/powerpc/configs/ep8248e_defconfig
+++ b/arch/powerpc/configs/ep8248e_defconfig
@@ -150,11 +150,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
CONFIG_PPC_82xx=y
diff --git a/arch/powerpc/configs/mgcoge_defconfig b/arch/powerpc/configs/mgcoge_defconfig
new file mode 100644
index 00000000000..cc9eaba8c9c
--- /dev/null
+++ b/arch/powerpc/configs/mgcoge_defconfig
@@ -0,0 +1,900 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc2
+# Thu May 22 08:18:47 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+# CONFIG_EXPERIMENTAL is not set
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# 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_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_MULTIPLATFORM is not set
+CONFIG_PPC_82xx=y
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_MPC8272_ADS is not set
+# CONFIG_PQ2FADS is not set
+# CONFIG_EP8248E is not set
+CONFIG_MGCOGE=y
+# CONFIG_PQ2ADS is not set
+CONFIG_8260=y
+CONFIG_8272=y
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_CPM2=y
+CONFIG_PPC_CPM_NEW_BINDING=y
+# CONFIG_FSL_ULI1575 is not set
+CONFIG_CPM=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+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_ZONE_DMA=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP 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=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_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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES 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_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+# CONFIG_MTD_BLOCK is not set
+# CONFIG_MTD_BLOCK_RO is not set
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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 is not set
+# 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=y
+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=y
+# 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
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# 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
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+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 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+# CONFIG_FS_ENET_HAS_FCC is not set
+# CONFIG_FS_ENET_MDIO_FCC is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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 is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG 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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=y
+# 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_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_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 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
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# 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=y
+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=y
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+CONFIG_BDI_SWITCH=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_PCBC=y
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/mgsuvd_defconfig b/arch/powerpc/configs/mgsuvd_defconfig
new file mode 100644
index 00000000000..3cd6ce4be82
--- /dev/null
+++ b/arch/powerpc/configs/mgsuvd_defconfig
@@ -0,0 +1,872 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.26-rc2
+# Wed May 21 13:30:33 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+# CONFIG_PPC_85xx is not set
+CONFIG_PPC_8xx=y
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_8xx=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+# CONFIG_EPOLL is not set
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=1
+# CONFIG_MODULES is not set
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG 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_CLASSIC_RCU=y
+
+#
+# Platform support
+#
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_PPC_MPC5121 is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+CONFIG_CPM1=y
+# CONFIG_MPC8XXFADS is not set
+# CONFIG_MPC86XADS is not set
+# CONFIG_MPC885ADS is not set
+# CONFIG_PPC_EP88XC is not set
+# CONFIG_PPC_ADDER875 is not set
+CONFIG_PPC_MGSUVD=y
+
+#
+# MPC8xx CPM Options
+#
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+CONFIG_8xx_CPU15=y
+# CONFIG_NO_UCODE_PATCH is not set
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+CONFIG_I2C_SPI_SMC1_UCODE_PATCH=y
+CONFIG_UCODE_PATCH=y
+# CONFIG_PQ2ADS is not set
+# CONFIG_IPIC is not set
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_PPC_CPM_NEW_BINDING=y
+# CONFIG_FSL_ULI1575 is not set
+CONFIG_CPM=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_TICK_ONESHOT is not set
+# CONFIG_NO_HZ is not set
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_FSL_SOC=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_PCI_QSPAN is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xfd000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# 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 is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=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
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS 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 is not set
+# 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=y
+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=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_CFI_FLAGADM 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
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD 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_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+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 is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+CONFIG_FIXED_PHY=y
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_B44 is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_HAS_SCC=y
+# CONFIG_FS_ENET_HAS_FEC is not set
+# CONFIG_FS_ENET_MDIO_FEC is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT 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_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+# CONFIG_I2C is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY 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_EXT4DEV_FS 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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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 is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 is not set
+# 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
+
+#
+# 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 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
+# CONFIG_SYSV68_PARTITION is not set
+# CONFIG_NLS is not set
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+# CONFIG_SAMPLES is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_VIRQ_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_PPC_CLOCK is not set
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/mpc8272_ads_defconfig b/arch/powerpc/configs/mpc8272_ads_defconfig
index 7c435c84c87..ff6f7c475f4 100644
--- a/arch/powerpc/configs/mpc8272_ads_defconfig
+++ b/arch/powerpc/configs/mpc8272_ads_defconfig
@@ -151,11 +151,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
CONFIG_PPC_82xx=y
diff --git a/arch/powerpc/configs/mpc83xx_defconfig b/arch/powerpc/configs/mpc83xx_defconfig
index 916e3df7cc4..991c9bda12a 100644
--- a/arch/powerpc/configs/mpc83xx_defconfig
+++ b/arch/powerpc/configs/mpc83xx_defconfig
@@ -166,11 +166,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_82xx is not set
diff --git a/arch/powerpc/configs/mpc86xx_defconfig b/arch/powerpc/configs/mpc86xx_defconfig
new file mode 100644
index 00000000000..9d4be820cf1
--- /dev/null
+++ b/arch/powerpc/configs/mpc86xx_defconfig
@@ -0,0 +1,1646 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.27-rc5
+# Tue Sep 23 23:28:38 2008
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+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_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DEFAULT_UIMAGE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+CONFIG_AUDIT=y
+# CONFIG_AUDITSYSCALL is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+# CONFIG_FAIR_GROUP_SCHED is not set
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+# CONFIG_MARKERS is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_DMA_ATTRS is not set
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_CLK is not set
+CONFIG_PROC_PAGE_MONITOR=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_LBD=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_MPC8xxx_GPIO is not set
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+CONFIG_MPC8641_HPCN=y
+CONFIG_SBC8641D=y
+CONFIG_MPC8610_HPCD=y
+CONFIG_GEF_SBC610=y
+CONFIG_MPC8641=y
+CONFIG_MPC8610=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+CONFIG_PPC_I8259=y
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+CONFIG_FSL_ULI1575=y
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=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_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+CONFIG_HAS_RAPIDIO=y
+# CONFIG_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=m
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+# 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=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+CONFIG_IP_SCTP=m
+# CONFIG_SCTP_DBG_MSG is not set
+# CONFIG_SCTP_DBG_OBJCNT is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+# 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_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+CONFIG_FIB_RULES=y
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# 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=y
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+CONFIG_SCSI_LOGGING=y
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+CONFIG_SATA_PMP=y
+CONFIG_SATA_AHCI=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+CONFIG_PATA_ALI=y
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+# CONFIG_MD is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+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
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_SFC is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# 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_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV 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_TABLET 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_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI 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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_NVRAM=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 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
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+CONFIG_SENSORS_EEPROM=y
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_DVB_CORE=m
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA8290=m
+CONFIG_MEDIA_TUNER_TDA9887=m
+CONFIG_MEDIA_TUNER_TEA5761=m
+CONFIG_MEDIA_TUNER_TEA5767=m
+CONFIG_MEDIA_TUNER_MT20XX=m
+CONFIG_MEDIA_TUNER_XC2028=m
+CONFIG_MEDIA_TUNER_XC5000=m
+CONFIG_DVB_CAPTURE_DRIVERS=y
+
+#
+# Supported SAA7146 based PCI Adapters
+#
+# CONFIG_TTPCI_EEPROM is not set
+# CONFIG_DVB_BUDGET_CORE is not set
+
+#
+# Supported USB Adapters
+#
+# CONFIG_DVB_USB is not set
+# CONFIG_DVB_TTUSB_BUDGET is not set
+# CONFIG_DVB_TTUSB_DEC is not set
+# CONFIG_DVB_CINERGYT2 is not set
+# CONFIG_DVB_SIANO_SMS1XXX is not set
+
+#
+# Supported FlexCopII (B2C2) Adapters
+#
+# CONFIG_DVB_B2C2_FLEXCOP is not set
+
+#
+# Supported BT878 Adapters
+#
+
+#
+# Supported Pluto2 Adapters
+#
+# CONFIG_DVB_PLUTO2 is not set
+
+#
+# Supported DVB Frontends
+#
+
+#
+# Customise DVB Frontends
+#
+# CONFIG_DVB_FE_CUSTOMISE is not set
+
+#
+# DVB-S (satellite) frontends
+#
+# CONFIG_DVB_CX24110 is not set
+# CONFIG_DVB_CX24123 is not set
+# CONFIG_DVB_MT312 is not set
+# CONFIG_DVB_S5H1420 is not set
+# CONFIG_DVB_STV0299 is not set
+# CONFIG_DVB_TDA8083 is not set
+# CONFIG_DVB_TDA10086 is not set
+# CONFIG_DVB_VES1X93 is not set
+# CONFIG_DVB_TUNER_ITD1000 is not set
+# CONFIG_DVB_TDA826X is not set
+# CONFIG_DVB_TUA6100 is not set
+
+#
+# DVB-T (terrestrial) frontends
+#
+# CONFIG_DVB_SP8870 is not set
+# CONFIG_DVB_SP887X is not set
+# CONFIG_DVB_CX22700 is not set
+# CONFIG_DVB_CX22702 is not set
+# CONFIG_DVB_DRX397XD is not set
+# CONFIG_DVB_L64781 is not set
+# CONFIG_DVB_TDA1004X is not set
+# CONFIG_DVB_NXT6000 is not set
+# CONFIG_DVB_MT352 is not set
+# CONFIG_DVB_ZL10353 is not set
+# CONFIG_DVB_DIB3000MB is not set
+# CONFIG_DVB_DIB3000MC is not set
+# CONFIG_DVB_DIB7000M is not set
+# CONFIG_DVB_DIB7000P is not set
+# CONFIG_DVB_TDA10048 is not set
+
+#
+# DVB-C (cable) frontends
+#
+# CONFIG_DVB_VES1820 is not set
+# CONFIG_DVB_TDA10021 is not set
+# CONFIG_DVB_TDA10023 is not set
+# CONFIG_DVB_STV0297 is not set
+
+#
+# ATSC (North American/Korean Terrestrial/Cable DTV) frontends
+#
+# CONFIG_DVB_NXT200X is not set
+# CONFIG_DVB_OR51211 is not set
+# CONFIG_DVB_OR51132 is not set
+# CONFIG_DVB_BCM3510 is not set
+# CONFIG_DVB_LGDT330X is not set
+# CONFIG_DVB_S5H1409 is not set
+# CONFIG_DVB_AU8522 is not set
+# CONFIG_DVB_S5H1411 is not set
+
+#
+# Digital terrestrial only tuners/PLL
+#
+# CONFIG_DVB_PLL is not set
+# CONFIG_DVB_TUNER_DIB0070 is not set
+
+#
+# SEC control devices for DVB-S
+#
+# CONFIG_DVB_LNBP21 is not set
+# CONFIG_DVB_ISL6405 is not set
+# CONFIG_DVB_ISL6421 is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_SOUND=y
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+# CONFIG_SND_SEQUENCER is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# 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
+CONFIG_SND_VMASTER=y
+CONFIG_SND_AC97_CODEC=y
+CONFIG_SND_DRIVERS=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
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_PCI=y
+# 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
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+CONFIG_SND_INTEL8X0=y
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# 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
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_PPC=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
+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
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+CONFIG_USB_EHCI_HCD_PPC_OF=y
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PPC_OF=y
+CONFIG_USB_OHCI_HCD_PPC_OF_BE=y
+CONFIG_USB_OHCI_HCD_PPC_OF_LE=y
+CONFIG_USB_OHCI_HCD_PCI=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# 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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_SIERRA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO 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_EXT4DEV_FS is not set
+CONFIG_JBD=y
+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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA 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=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_HFSPLUS_FS=m
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=y
+CONFIG_VXFS_FS=m
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+# CONFIG_ROMFS_FS is not set
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# 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
+
+#
+# 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=y
+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 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
+# CONFIG_SYSV68_PARTITION is not set
+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=m
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC_T10DIF=y
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FTRACE=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+# CONFIG_FTRACE is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff --git a/arch/powerpc/configs/pq2fads_defconfig b/arch/powerpc/configs/pq2fads_defconfig
index b390b747664..7e17862c38b 100644
--- a/arch/powerpc/configs/pq2fads_defconfig
+++ b/arch/powerpc/configs/pq2fads_defconfig
@@ -152,11 +152,11 @@ CONFIG_CLASSIC_RCU=y
#
CONFIG_PPC_MULTIPLATFORM=y
CONFIG_CLASSIC32=y
-CONFIG_PPC_CHRP=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
# CONFIG_MPC5121_ADS is not set
# CONFIG_MPC5121_GENERIC is not set
# CONFIG_PPC_MPC52xx is not set
-CONFIG_PPC_PMAC=y
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
CONFIG_PPC_82xx=y
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index ef8a248dfd5..1e94b07a020 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -62,6 +62,7 @@ enum powerpc_pmc_type {
PPC_PMC_DEFAULT = 0,
PPC_PMC_IBM = 1,
PPC_PMC_PA6T = 2,
+ PPC_PMC_G4 = 3,
};
struct pt_regs;
@@ -192,6 +193,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_NO_SLBIE_B LONG_ASM_CONST(0x0008000000000000)
#define CPU_FTR_VSX LONG_ASM_CONST(0x0010000000000000)
#define CPU_FTR_SAO LONG_ASM_CONST(0x0020000000000000)
+#define CPU_FTR_CP_USE_DCBTZ LONG_ASM_CONST(0x0040000000000000)
#ifndef __ASSEMBLY__
@@ -387,10 +389,11 @@ extern const char *powerpc_base_platform;
CPU_FTR_MMCRA | CPU_FTR_CTRL)
#define CPU_FTRS_POWER4 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
- CPU_FTR_MMCRA)
+ CPU_FTR_MMCRA | CPU_FTR_CP_USE_DCBTZ)
#define CPU_FTRS_PPC970 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
- CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA)
+ CPU_FTR_ALTIVEC_COMP | CPU_FTR_CAN_NAP | CPU_FTR_MMCRA | \
+ CPU_FTR_CP_USE_DCBTZ)
#define CPU_FTRS_POWER5 (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_MMCRA | CPU_FTR_SMT | \
@@ -411,7 +414,8 @@ extern const char *powerpc_base_platform;
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
- CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | CPU_FTR_CELL_TB_BUG)
+ CPU_FTR_PAUSE_ZERO | CPU_FTR_CI_LARGE_PAGE | \
+ CPU_FTR_CELL_TB_BUG | CPU_FTR_CP_USE_DCBTZ)
#define CPU_FTRS_PA6T (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_HPTE_TABLE | CPU_FTR_PPCAS_ARCH_V2 | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_CI_LARGE_PAGE | \
diff --git a/arch/powerpc/include/asm/dcr-regs.h b/arch/powerpc/include/asm/dcr-regs.h
index f15296cf359..828e3aa1f2f 100644
--- a/arch/powerpc/include/asm/dcr-regs.h
+++ b/arch/powerpc/include/asm/dcr-regs.h
@@ -68,6 +68,13 @@
#define SDR0_UART3 0x0123
#define SDR0_CUST0 0x4000
+/* SDR for 405EZ */
+#define DCRN_SDR_ICINTSTAT 0x4510
+#define ICINTSTAT_ICRX 0x80000000
+#define ICINTSTAT_ICTX0 0x40000000
+#define ICINTSTAT_ICTX1 0x20000000
+#define ICINTSTAT_ICTX 0x60000000
+
/* SDRs (460EX/460GT) */
#define SDR0_ETH_CFG 0x4103
#define SDR0_ETH_CFG_ECS 0x00000100 /* EMAC int clk source */
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h
index 228ab2a315b..dfd504caccc 100644
--- a/arch/powerpc/include/asm/device.h
+++ b/arch/powerpc/include/asm/device.h
@@ -16,9 +16,6 @@ struct dev_archdata {
/* DMA operations on that device */
struct dma_mapping_ops *dma_ops;
void *dma_data;
-
- /* NUMA node if applicable */
- int numa_node;
};
#endif /* _ASM_POWERPC_DEVICE_H */
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index c7ca45f97dd..fddb229bd74 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -44,8 +44,6 @@ extern void __dma_sync_page(struct page *page, unsigned long offset,
#endif /* ! CONFIG_NOT_COHERENT_CACHE */
-#ifdef CONFIG_PPC64
-
static inline unsigned long device_to_mask(struct device *dev)
{
if (dev->dma_mask && *dev->dma_mask)
@@ -76,8 +74,24 @@ struct dma_mapping_ops {
struct dma_attrs *attrs);
int (*dma_supported)(struct device *dev, u64 mask);
int (*set_dma_mask)(struct device *dev, u64 dma_mask);
+ dma_addr_t (*map_page)(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
+ void (*unmap_page)(struct device *dev,
+ dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
};
+/*
+ * Available generic sets of operations
+ */
+#ifdef CONFIG_PPC64
+extern struct dma_mapping_ops dma_iommu_ops;
+#endif
+extern struct dma_mapping_ops dma_direct_ops;
+
static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
{
/* We don't handle the NULL dev case for ISA for now. We could
@@ -85,8 +99,19 @@ static inline struct dma_mapping_ops *get_dma_ops(struct device *dev)
* only ISA DMA device we support is the floppy and we have a hack
* in the floppy driver directly to get a device for us.
*/
- if (unlikely(dev == NULL || dev->archdata.dma_ops == NULL))
+
+ if (unlikely(dev == NULL) || dev->archdata.dma_ops == NULL) {
+#ifdef CONFIG_PPC64
return NULL;
+#else
+ /* Use default on 32-bit if dma_ops is not set up */
+ /* TODO: Long term, we should fix drivers so that dev and
+ * archdata dma_ops are set up for all buses.
+ */
+ return &dma_direct_ops;
+#endif
+ }
+
return dev->archdata.dma_ops;
}
@@ -123,6 +148,12 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask)
return 0;
}
+/*
+ * TODO: map_/unmap_single will ideally go away, to be completely
+ * replaced by map/unmap_page. Until then, we allow dma_ops to have
+ * one or the other, or both by checking to see if the specific
+ * function requested exists; and if not, falling back on the other set.
+ */
static inline dma_addr_t dma_map_single_attrs(struct device *dev,
void *cpu_addr,
size_t size,
@@ -132,7 +163,14 @@ static inline dma_addr_t dma_map_single_attrs(struct device *dev,
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
- return dma_ops->map_single(dev, cpu_addr, size, direction, attrs);
+
+ if (dma_ops->map_single)
+ return dma_ops->map_single(dev, cpu_addr, size, direction,
+ attrs);
+
+ return dma_ops->map_page(dev, virt_to_page(cpu_addr),
+ (unsigned long)cpu_addr % PAGE_SIZE, size,
+ direction, attrs);
}
static inline void dma_unmap_single_attrs(struct device *dev,
@@ -144,7 +182,13 @@ static inline void dma_unmap_single_attrs(struct device *dev,
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
- dma_ops->unmap_single(dev, dma_addr, size, direction, attrs);
+
+ if (dma_ops->unmap_single) {
+ dma_ops->unmap_single(dev, dma_addr, size, direction, attrs);
+ return;
+ }
+
+ dma_ops->unmap_page(dev, dma_addr, size, direction, attrs);
}
static inline dma_addr_t dma_map_page_attrs(struct device *dev,
@@ -156,8 +200,13 @@ static inline dma_addr_t dma_map_page_attrs(struct device *dev,
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
+
+ if (dma_ops->map_page)
+ return dma_ops->map_page(dev, page, offset, size, direction,
+ attrs);
+
return dma_ops->map_single(dev, page_address(page) + offset, size,
- direction, attrs);
+ direction, attrs);
}
static inline void dma_unmap_page_attrs(struct device *dev,
@@ -169,6 +218,12 @@ static inline void dma_unmap_page_attrs(struct device *dev,
struct dma_mapping_ops *dma_ops = get_dma_ops(dev);
BUG_ON(!dma_ops);
+
+ if (dma_ops->unmap_page) {
+ dma_ops->unmap_page(dev, dma_address, size, direction, attrs);
+ return;
+ }
+
dma_ops->unmap_single(dev, dma_address, size, direction, attrs);
}
@@ -253,126 +308,6 @@ static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
dma_unmap_sg_attrs(dev, sg, nhwentries, direction, NULL);
}
-/*
- * Available generic sets of operations
- */
-extern struct dma_mapping_ops dma_iommu_ops;
-extern struct dma_mapping_ops dma_direct_ops;
-
-#else /* CONFIG_PPC64 */
-
-#define dma_supported(dev, mask) (1)
-
-static inline int dma_set_mask(struct device *dev, u64 dma_mask)
-{
- if (!dev->dma_mask || !dma_supported(dev, mask))
- return -EIO;
-
- *dev->dma_mask = dma_mask;
-
- return 0;
-}
-
-static inline void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t * dma_handle,
- gfp_t gfp)
-{
-#ifdef CONFIG_NOT_COHERENT_CACHE
- return __dma_alloc_coherent(size, dma_handle, gfp);
-#else
- void *ret;
- /* ignore region specifiers */
- gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
-
- if (dev == NULL || dev->coherent_dma_mask < 0xffffffff)
- gfp |= GFP_DMA;
-
- ret = (void *)__get_free_pages(gfp, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
- }
-
- return ret;
-#endif
-}
-
-static inline void
-dma_free_coherent(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
-{
-#ifdef CONFIG_NOT_COHERENT_CACHE
- __dma_free_coherent(size, vaddr);
-#else
- free_pages((unsigned long)vaddr, get_order(size));
-#endif
-}
-
-static inline dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
- enum dma_data_direction direction)
-{
- BUG_ON(direction == DMA_NONE);
-
- __dma_sync(ptr, size, direction);
-
- return virt_to_bus(ptr);
-}
-
-static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction direction)
-{
- /* We do nothing. */
-}
-
-static inline dma_addr_t
-dma_map_page(struct device *dev, struct page *page,
- unsigned long offset, size_t size,
- enum dma_data_direction direction)
-{
- BUG_ON(direction == DMA_NONE);
-
- __dma_sync_page(page, offset, size, direction);
-
- return page_to_bus(page) + offset;
-}
-
-static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
- size_t size,
- enum dma_data_direction direction)
-{
- /* We do nothing. */
-}
-
-static inline int
-dma_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
- enum dma_data_direction direction)
-{
- struct scatterlist *sg;
- int i;
-
- BUG_ON(direction == DMA_NONE);
-
- for_each_sg(sgl, sg, nents, i) {
- BUG_ON(!sg_page(sg));
- __dma_sync_page(sg_page(sg), sg->offset, sg->length, direction);
- sg->dma_address = page_to_bus(sg_page(sg)) + sg->offset;
- }
-
- return nents;
-}
-
-static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nhwentries,
- enum dma_data_direction direction)
-{
- /* We don't do anything here. */
-}
-
-#endif /* CONFIG_PPC64 */
-
static inline void dma_sync_single_for_cpu(struct device *dev,
dma_addr_t dma_handle, size_t size,
enum dma_data_direction direction)
diff --git a/arch/powerpc/include/asm/exception.h b/arch/powerpc/include/asm/exception.h
index 329148b5acc..d3d4534e3c7 100644
--- a/arch/powerpc/include/asm/exception.h
+++ b/arch/powerpc/include/asm/exception.h
@@ -53,14 +53,8 @@
* low halfword of the address, but for Kdump we need the whole low
* word.
*/
-#ifdef CONFIG_CRASH_DUMP
#define LOAD_HANDLER(reg, label) \
- oris reg,reg,(label)@h; /* virt addr of handler ... */ \
- ori reg,reg,(label)@l; /* .. and the rest */
-#else
-#define LOAD_HANDLER(reg, label) \
- ori reg,reg,(label)@l; /* virt addr of handler ... */
-#endif
+ addi reg,reg,(label)-_stext; /* virt addr of handler ... */
#define EXCEPTION_PROLOG_1(area) \
mfspr r13,SPRN_SPRG3; /* get paca address into r13 */ \
@@ -72,37 +66,12 @@
std r9,area+EX_R13(r13); \
mfcr r9
-/*
- * Equal to EXCEPTION_PROLOG_PSERIES, except that it forces 64bit mode.
- * The firmware calls the registered system_reset_fwnmi and
- * machine_check_fwnmi handlers in 32bit mode if the cpu happens to run
- * a 32bit application at the time of the event.
- * This firmware bug is present on POWER4 and JS20.
- */
-#define EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(area, label) \
- EXCEPTION_PROLOG_1(area); \
- clrrdi r12,r13,32; /* get high part of &label */ \
- mfmsr r10; \
- /* force 64bit mode */ \
- li r11,5; /* MSR_SF_LG|MSR_ISF_LG */ \
- rldimi r10,r11,61,0; /* insert into top 3 bits */ \
- /* done 64bit mode */ \
- mfspr r11,SPRN_SRR0; /* save SRR0 */ \
- LOAD_HANDLER(r12,label) \
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
- mtspr SPRN_SRR0,r12; \
- mfspr r12,SPRN_SRR1; /* and SRR1 */ \
- mtspr SPRN_SRR1,r10; \
- rfid; \
- b . /* prevent speculative execution */
-
#define EXCEPTION_PROLOG_PSERIES(area, label) \
EXCEPTION_PROLOG_1(area); \
- clrrdi r12,r13,32; /* get high part of &label */ \
- mfmsr r10; \
+ ld r12,PACAKBASE(r13); /* get high part of &label */ \
+ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
mfspr r11,SPRN_SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label) \
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
mtspr SPRN_SRR0,r12; \
mfspr r12,SPRN_SRR1; /* and SRR1 */ \
mtspr SPRN_SRR1,r10; \
@@ -210,11 +179,10 @@ label##_pSeries: \
std r10,PACA_EXGEN+EX_R13(r13); \
std r11,PACA_EXGEN+EX_R11(r13); \
std r12,PACA_EXGEN+EX_R12(r13); \
- clrrdi r12,r13,32; /* get high part of &label */ \
- mfmsr r10; \
+ ld r12,PACAKBASE(r13); /* get high part of &label */ \
+ ld r10,PACAKMSR(r13); /* get MSR value for kernel */ \
mfspr r11,SPRN_SRR0; /* save SRR0 */ \
LOAD_HANDLER(r12,label##_common) \
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI; \
mtspr SPRN_SRR0,r12; \
mfspr r12,SPRN_SRR1; /* and SRR1 */ \
mtspr SPRN_SRR1,r10; \
diff --git a/arch/powerpc/include/asm/fsl_lbc.h b/arch/powerpc/include/asm/fsl_lbc.h
index 303f5484c05..63a4f779f53 100644
--- a/arch/powerpc/include/asm/fsl_lbc.h
+++ b/arch/powerpc/include/asm/fsl_lbc.h
@@ -23,9 +23,9 @@
#ifndef __ASM_FSL_LBC_H
#define __ASM_FSL_LBC_H
+#include <linux/compiler.h>
#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
struct fsl_lbc_bank {
__be32 br; /**< Base Register */
@@ -227,9 +227,6 @@ struct fsl_lbc_regs {
u8 res8[0xF00];
};
-extern struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-extern spinlock_t fsl_lbc_lock;
-
/*
* FSL UPM routines
*/
@@ -268,44 +265,7 @@ static inline void fsl_upm_end_pattern(struct fsl_upm *upm)
cpu_relax();
}
-/**
- * fsl_upm_run_pattern - actually run an UPM pattern
- * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
- * @io_base: remapped pointer to where memory access should happen
- * @mar: MAR register content during pattern execution
- *
- * This function triggers dummy write to the memory specified by the io_base,
- * thus UPM pattern actually executed. Note that mar usage depends on the
- * pre-programmed AMX bits in the UPM RAM.
- */
-static inline int fsl_upm_run_pattern(struct fsl_upm *upm,
- void __iomem *io_base, u32 mar)
-{
- int ret = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&fsl_lbc_lock, flags);
-
- out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
-
- switch (upm->width) {
- case 8:
- out_8(io_base, 0x0);
- break;
- case 16:
- out_be16(io_base, 0x0);
- break;
- case 32:
- out_be32(io_base, 0x0);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- spin_unlock_irqrestore(&fsl_lbc_lock, flags);
-
- return ret;
-}
+extern int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base,
+ u32 mar);
#endif /* __ASM_FSL_LBC_H */
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index 5d99b6489d5..91c589520c0 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -84,7 +84,7 @@ static inline void *kmap_atomic_prot(struct page *page, enum km_type type, pgpro
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte-idx)));
#endif
- set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
+ __set_pte_at(&init_mm, vaddr, kmap_pte-idx, mk_pte(page, prot));
flush_tlb_page(NULL, vaddr);
return (void*) vaddr;
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 77c7fa025e6..08266d2728b 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -711,7 +711,7 @@ static inline void * phys_to_virt(unsigned long address)
/*
* Change "struct page" to physical address.
*/
-#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+#define page_to_phys(page) ((phys_addr_t)page_to_pfn(page) << PAGE_SHIFT)
/* We do NOT want virtual merging, it would put too much pressure on
* our iommu allocator. Instead, we want drivers to be smart enough
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h
index a372f76836c..0a5137676e1 100644
--- a/arch/powerpc/include/asm/irq.h
+++ b/arch/powerpc/include/asm/irq.h
@@ -236,15 +236,27 @@ extern unsigned int irq_find_mapping(struct irq_host *host,
extern unsigned int irq_create_direct_mapping(struct irq_host *host);
/**
- * irq_radix_revmap - Find a linux virq from a hw irq number.
+ * irq_radix_revmap_insert - Insert a hw irq to linux virq number mapping.
+ * @host: host owning this hardware interrupt
+ * @virq: linux irq number
+ * @hwirq: hardware irq number in that host space
+ *
+ * This is for use by irq controllers that use a radix tree reverse
+ * mapping for fast lookup.
+ */
+extern void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+ irq_hw_number_t hwirq);
+
+/**
+ * irq_radix_revmap_lookup - Find a linux virq from a hw irq number.
* @host: host owning this hardware interrupt
* @hwirq: hardware irq number in that host space
*
* This is a fast path, for use by irq controller code that uses radix tree
* revmaps
*/
-extern unsigned int irq_radix_revmap(struct irq_host *host,
- irq_hw_number_t hwirq);
+extern unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+ irq_hw_number_t hwirq);
/**
* irq_linear_revmap - Find a linux virq from a hw irq number.
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h
index 893aafd87fd..2740c44ff71 100644
--- a/arch/powerpc/include/asm/machdep.h
+++ b/arch/powerpc/include/asm/machdep.h
@@ -88,8 +88,6 @@ struct machdep_calls {
unsigned long (*tce_get)(struct iommu_table *tbl,
long index);
void (*tce_flush)(struct iommu_table *tbl);
- void (*pci_dma_dev_setup)(struct pci_dev *dev);
- void (*pci_dma_bus_setup)(struct pci_bus *bus);
void __iomem * (*ioremap)(phys_addr_t addr, unsigned long size,
unsigned long flags);
@@ -101,6 +99,9 @@ struct machdep_calls {
#endif
#endif /* CONFIG_PPC64 */
+ void (*pci_dma_dev_setup)(struct pci_dev *dev);
+ void (*pci_dma_bus_setup)(struct pci_bus *bus);
+
int (*probe)(void);
void (*setup_arch)(void); /* Optional, may be NULL */
void (*init_early)(void);
diff --git a/arch/powerpc/include/asm/mman.h b/arch/powerpc/include/asm/mman.h
index 9209f755763..e7b99bac9f4 100644
--- a/arch/powerpc/include/asm/mman.h
+++ b/arch/powerpc/include/asm/mman.h
@@ -44,7 +44,7 @@ static inline unsigned long arch_calc_vm_prot_bits(unsigned long prot)
static inline pgprot_t arch_vm_get_page_prot(unsigned long vm_flags)
{
- return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : 0;
+ return (vm_flags & VM_SAO) ? __pgprot(_PAGE_SAO) : __pgprot(0);
}
#define arch_vm_get_page_prot(vm_flags) arch_vm_get_page_prot(vm_flags)
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h
index c2df53c5ceb..5a441742ffb 100644
--- a/arch/powerpc/include/asm/mmu-hash64.h
+++ b/arch/powerpc/include/asm/mmu-hash64.h
@@ -437,7 +437,7 @@ typedef struct {
})
#endif /* 1 */
-/* This is only valid for addresses >= KERNELBASE */
+/* This is only valid for addresses >= PAGE_OFFSET */
static inline unsigned long get_kernel_vsid(unsigned long ea, int ssize)
{
if (ssize == MMU_SEGSIZE_256M)
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h
index fe566a348a8..34d9ac433ac 100644
--- a/arch/powerpc/include/asm/mpic.h
+++ b/arch/powerpc/include/asm/mpic.h
@@ -5,6 +5,7 @@
#include <linux/irq.h>
#include <linux/sysdev.h>
#include <asm/dcr.h>
+#include <asm/msi_bitmap.h>
/*
* Global registers
@@ -301,8 +302,7 @@ struct mpic
#endif
#ifdef CONFIG_PCI_MSI
- spinlock_t bitmap_lock;
- unsigned long *hwirq_bitmap;
+ struct msi_bitmap msi_bitmap;
#endif
#ifdef CONFIG_MPIC_BROKEN_REGREAD
diff --git a/arch/powerpc/include/asm/msi_bitmap.h b/arch/powerpc/include/asm/msi_bitmap.h
new file mode 100644
index 00000000000..97ac3f46ae0
--- /dev/null
+++ b/arch/powerpc/include/asm/msi_bitmap.h
@@ -0,0 +1,35 @@
+#ifndef _POWERPC_SYSDEV_MSI_BITMAP_H
+#define _POWERPC_SYSDEV_MSI_BITMAP_H
+
+/*
+ * Copyright 2008, Michael Ellerman, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/of.h>
+#include <asm/irq.h>
+
+struct msi_bitmap {
+ struct device_node *of_node;
+ unsigned long *bitmap;
+ spinlock_t lock;
+ unsigned int irq_count;
+};
+
+int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num);
+void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset,
+ unsigned int num);
+void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq);
+
+int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp);
+
+int msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
+ struct device_node *of_node);
+void msi_bitmap_free(struct msi_bitmap *bmp);
+
+#endif /* _POWERPC_SYSDEV_MSI_BITMAP_H */
diff --git a/arch/powerpc/include/asm/of_device.h b/arch/powerpc/include/asm/of_device.h
index 3c123990ca2..a64debf177d 100644
--- a/arch/powerpc/include/asm/of_device.h
+++ b/arch/powerpc/include/asm/of_device.h
@@ -24,8 +24,5 @@ extern struct of_device *of_device_alloc(struct device_node *np,
extern int of_device_uevent(struct device *dev,
struct kobj_uevent_env *env);
-/* This is just here during the transition */
-#include <linux/of_device.h>
-
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_OF_DEVICE_H */
diff --git a/arch/powerpc/include/asm/of_platform.h b/arch/powerpc/include/asm/of_platform.h
index 18659ef7213..53b46507ffd 100644
--- a/arch/powerpc/include/asm/of_platform.h
+++ b/arch/powerpc/include/asm/of_platform.h
@@ -11,9 +11,6 @@
*
*/
-/* This is just here during the transition */
-#include <linux/of_platform.h>
-
/* Platform drivers register/unregister */
static inline int of_register_platform_driver(struct of_platform_driver *drv)
{
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 6493a395508..082b3aedf14 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -62,6 +62,8 @@ struct paca_struct {
u16 paca_index; /* Logical processor number */
u64 kernel_toc; /* Kernel TOC address */
+ u64 kernelbase; /* Base address of kernel */
+ u64 kernel_msr; /* MSR while running in kernel */
u64 stab_real; /* Absolute address of segment table */
u64 stab_addr; /* Virtual address of segment table */
void *emergency_sp; /* pointer to emergency stack */
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index e088545cb3f..64e144505f6 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -71,15 +71,21 @@
#define PAGE_OFFSET ASM_CONST(CONFIG_PAGE_OFFSET)
#define LOAD_OFFSET ASM_CONST((CONFIG_KERNEL_START-CONFIG_PHYSICAL_START))
-#if defined(CONFIG_RELOCATABLE) && defined(CONFIG_FLATMEM)
+#if defined(CONFIG_RELOCATABLE)
#ifndef __ASSEMBLY__
extern phys_addr_t memstart_addr;
extern phys_addr_t kernstart_addr;
#endif
#define PHYSICAL_START kernstart_addr
-#define MEMORY_START memstart_addr
#else
#define PHYSICAL_START ASM_CONST(CONFIG_PHYSICAL_START)
+#endif
+
+#ifdef CONFIG_PPC64
+#define MEMORY_START 0UL
+#elif defined(CONFIG_RELOCATABLE)
+#define MEMORY_START memstart_addr
+#else
#define MEMORY_START (PHYSICAL_START + PAGE_OFFSET - KERNELBASE)
#endif
@@ -92,8 +98,8 @@ extern phys_addr_t kernstart_addr;
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
-#define __va(x) ((void *)((unsigned long)(x) - PHYSICAL_START + KERNELBASE))
-#define __pa(x) ((unsigned long)(x) + PHYSICAL_START - KERNELBASE)
+#define __va(x) ((void *)((unsigned long)(x) + PAGE_OFFSET - MEMORY_START))
+#define __pa(x) ((unsigned long)(x) - PAGE_OFFSET + MEMORY_START)
/*
* Unfortunately the PLT is in the BSS in the PPC32 ELF ABI,
diff --git a/arch/powerpc/include/asm/page_32.h b/arch/powerpc/include/asm/page_32.h
index ebfae530a37..d77072a32cc 100644
--- a/arch/powerpc/include/asm/page_32.h
+++ b/arch/powerpc/include/asm/page_32.h
@@ -13,10 +13,16 @@
#define ARCH_KMALLOC_MINALIGN L1_CACHE_BYTES
#endif
+#ifdef CONFIG_PTE_64BIT
+#define PTE_FLAGS_OFFSET 4 /* offset of PTE flags, in bytes */
+#else
+#define PTE_FLAGS_OFFSET 0
+#endif
+
#ifndef __ASSEMBLY__
/*
* The basic type of a PTE - 64 bits for those CPUs with > 32 bit
- * physical addressing. For now this just the IBM PPC440.
+ * physical addressing.
*/
#ifdef CONFIG_PTE_64BIT
typedef unsigned long long pte_basic_t;
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index a05a942b1c2..0e52c7828ea 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -60,6 +60,14 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
return channel ? 15 : 14;
}
+#ifdef CONFIG_PCI
+extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
+extern struct dma_mapping_ops *get_pci_dma_ops(void);
+#else /* CONFIG_PCI */
+#define set_pci_dma_ops(d)
+#define get_pci_dma_ops() NULL
+#endif
+
#ifdef CONFIG_PPC64
/*
@@ -70,9 +78,6 @@ static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
#define PCI_DISABLE_MWI
#ifdef CONFIG_PCI
-extern void set_pci_dma_ops(struct dma_mapping_ops *dma_ops);
-extern struct dma_mapping_ops *get_pci_dma_ops(void);
-
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
unsigned long *strategy_parameter)
@@ -89,9 +94,6 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
*strat = PCI_DMA_BURST_MULTIPLE;
*strategy_parameter = cacheline_size;
}
-#else /* CONFIG_PCI */
-#define set_pci_dma_ops(d)
-#define get_pci_dma_ops() NULL
#endif
#else /* 32-bit */
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h
index 6fe39e32704..6ab7c67cb5a 100644
--- a/arch/powerpc/include/asm/pgtable-ppc32.h
+++ b/arch/powerpc/include/asm/pgtable-ppc32.h
@@ -261,6 +261,7 @@ extern int icache_44x_need_flush;
#define _PAGE_HWEXEC 0x00000004 /* H: Execute permission */
#define _PAGE_ACCESSED 0x00000008 /* S: Page referenced */
#define _PAGE_DIRTY 0x00000010 /* S: Page dirty */
+#define _PAGE_SPECIAL 0x00000020 /* S: Special page */
#define _PAGE_USER 0x00000040 /* S: User page */
#define _PAGE_ENDIAN 0x00000080 /* H: E bit */
#define _PAGE_GUARDED 0x00000100 /* H: G bit */
@@ -276,6 +277,7 @@ extern int icache_44x_need_flush;
/* ERPN in a PTE never gets cleared, ignore it */
#define _PTE_NONE_MASK 0xffffffff00000000ULL
+#define __HAVE_ARCH_PTE_SPECIAL
#elif defined(CONFIG_FSL_BOOKE)
/*
@@ -305,6 +307,7 @@ extern int icache_44x_need_flush;
#define _PAGE_COHERENT 0x00100 /* H: M bit */
#define _PAGE_NO_CACHE 0x00200 /* H: I bit */
#define _PAGE_WRITETHRU 0x00400 /* H: W bit */
+#define _PAGE_SPECIAL 0x00800 /* S: Special page */
#ifdef CONFIG_PTE_64BIT
/* ERPN in a PTE never gets cleared, ignore it */
@@ -315,6 +318,8 @@ extern int icache_44x_need_flush;
#define _PMD_PRESENT_MASK (PAGE_MASK)
#define _PMD_BAD (~PAGE_MASK)
+#define __HAVE_ARCH_PTE_SPECIAL
+
#elif defined(CONFIG_8xx)
/* Definitions for 8xx embedded chips. */
#define _PAGE_PRESENT 0x0001 /* Page is valid */
@@ -362,8 +367,14 @@ extern int icache_44x_need_flush;
#define _PAGE_ACCESSED 0x100 /* R: page referenced */
#define _PAGE_EXEC 0x200 /* software: i-cache coherency required */
#define _PAGE_RW 0x400 /* software: user write access allowed */
+#define _PAGE_SPECIAL 0x800 /* software: Special page */
+#ifdef CONFIG_PTE_64BIT
+/* We never clear the high word of the pte */
+#define _PTE_NONE_MASK (0xffffffff00000000ULL | _PAGE_HASHPTE)
+#else
#define _PTE_NONE_MASK _PAGE_HASHPTE
+#endif
#define _PMD_PRESENT 0
#define _PMD_PRESENT_MASK (PAGE_MASK)
@@ -372,6 +383,8 @@ extern int icache_44x_need_flush;
/* Hash table based platforms need atomic updates of the linux PTE */
#define PTE_ATOMIC_UPDATES 1
+#define __HAVE_ARCH_PTE_SPECIAL
+
#endif
/*
@@ -404,6 +417,9 @@ extern int icache_44x_need_flush;
#ifndef _PAGE_WRITETHRU
#define _PAGE_WRITETHRU 0
#endif
+#ifndef _PAGE_SPECIAL
+#define _PAGE_SPECIAL 0
+#endif
#ifndef _PMD_PRESENT_MASK
#define _PMD_PRESENT_MASK _PMD_PRESENT
#endif
@@ -415,11 +431,11 @@ extern int icache_44x_need_flush;
#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define PAGE_PROT_BITS __pgprot(_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
- _PAGE_WRITETHRU | _PAGE_ENDIAN | \
- _PAGE_USER | _PAGE_ACCESSED | \
- _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
- _PAGE_EXEC | _PAGE_HWEXEC)
+#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
+ _PAGE_WRITETHRU | _PAGE_ENDIAN | \
+ _PAGE_USER | _PAGE_ACCESSED | \
+ _PAGE_RW | _PAGE_HWWRITE | _PAGE_DIRTY | \
+ _PAGE_EXEC | _PAGE_HWEXEC)
/*
* Note: the _PAGE_COHERENT bit automatically gets set in the hardware
* PTE if CONFIG_SMP is defined (hash_page does this); there is no need
@@ -517,7 +533,8 @@ extern unsigned long bad_call_to_PMD_PAGE_SIZE(void);
#define pte_none(pte) ((pte_val(pte) & ~_PTE_NONE_MASK) == 0)
#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT)
-#define pte_clear(mm,addr,ptep) do { set_pte_at((mm), (addr), (ptep), __pte(0)); } while (0)
+#define pte_clear(mm, addr, ptep) \
+ do { pte_update(ptep, ~_PAGE_HASHPTE, 0); } while (0)
#define pmd_none(pmd) (!pmd_val(pmd))
#define pmd_bad(pmd) (pmd_val(pmd) & _PMD_BAD)
@@ -533,7 +550,7 @@ static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
-static inline int pte_special(pte_t pte) { return 0; }
+static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
static inline void pte_uncache(pte_t pte) { pte_val(pte) |= _PAGE_NO_CACHE; }
static inline void pte_cache(pte_t pte) { pte_val(pte) &= ~_PAGE_NO_CACHE; }
@@ -552,10 +569,10 @@ static inline pte_t pte_mkdirty(pte_t pte) {
static inline pte_t pte_mkyoung(pte_t pte) {
pte_val(pte) |= _PAGE_ACCESSED; return pte; }
static inline pte_t pte_mkspecial(pte_t pte) {
- return pte; }
-static inline unsigned long pte_pgprot(pte_t pte)
+ pte_val(pte) |= _PAGE_SPECIAL; return pte; }
+static inline pgprot_t pte_pgprot(pte_t pte)
{
- return __pgprot(pte_val(pte)) & PAGE_PROT_BITS;
+ return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
}
static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
@@ -575,6 +592,10 @@ extern int flush_hash_pages(unsigned context, unsigned long va,
extern void add_hash_page(unsigned context, unsigned long va,
unsigned long pmdval);
+/* Flush an entry from the TLB/hash table */
+extern void flush_hash_entry(struct mm_struct *mm, pte_t *ptep,
+ unsigned long address);
+
/*
* Atomic PTE updates.
*
@@ -612,9 +633,6 @@ static inline unsigned long pte_update(pte_t *p,
return old;
}
#else /* CONFIG_PTE_64BIT */
-/* TODO: Change that to only modify the low word and move set_pte_at()
- * out of line
- */
static inline unsigned long long pte_update(pte_t *p,
unsigned long clr,
unsigned long set)
@@ -652,14 +670,36 @@ static inline unsigned long long pte_update(pte_t *p,
* On machines which use an MMU hash table we avoid changing the
* _PAGE_HASHPTE bit.
*/
-static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+
+static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte)
{
-#if _PAGE_HASHPTE != 0
+#if (_PAGE_HASHPTE != 0) && defined(CONFIG_SMP) && !defined(CONFIG_PTE_64BIT)
pte_update(ptep, ~_PAGE_HASHPTE, pte_val(pte) & ~_PAGE_HASHPTE);
+#elif defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+#if _PAGE_HASHPTE != 0
+ if (pte_val(*ptep) & _PAGE_HASHPTE)
+ flush_hash_entry(mm, ptep, addr);
+#endif
+ __asm__ __volatile__("\
+ stw%U0%X0 %2,%0\n\
+ eieio\n\
+ stw%U0%X0 %L2,%1"
+ : "=m" (*ptep), "=m" (*((unsigned char *)ptep+4))
+ : "r" (pte) : "memory");
#else
- *ptep = pte;
+ *ptep = __pte((pte_val(*ptep) & _PAGE_HASHPTE)
+ | (pte_val(pte) & ~_PAGE_HASHPTE));
+#endif
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+#if defined(CONFIG_PTE_64BIT) && defined(CONFIG_SMP)
+ WARN_ON(pte_present(*ptep));
#endif
+ __set_pte_at(mm, addr, ptep, pte);
}
/*
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index 4597c491e9b..4c0a8c62859 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -117,10 +117,10 @@
#define PAGE_AGP __pgprot(_PAGE_BASE | _PAGE_WRENABLE | _PAGE_NO_CACHE)
#define HAVE_PAGE_AGP
-#define PAGE_PROT_BITS __pgprot(_PAGE_GUARDED | _PAGE_COHERENT | \
- _PAGE_NO_CACHE | _PAGE_WRITETHRU | \
- _PAGE_4K_PFN | _PAGE_RW | _PAGE_USER | \
- _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
+#define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | \
+ _PAGE_NO_CACHE | _PAGE_WRITETHRU | \
+ _PAGE_4K_PFN | _PAGE_RW | _PAGE_USER | \
+ _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_EXEC)
/* PTEIDX nibble */
#define _PTEIDX_SECONDARY 0x8
#define _PTEIDX_GROUP_IX 0x7
@@ -264,9 +264,9 @@ static inline pte_t pte_mkhuge(pte_t pte) {
return pte; }
static inline pte_t pte_mkspecial(pte_t pte) {
pte_val(pte) |= _PAGE_SPECIAL; return pte; }
-static inline unsigned long pte_pgprot(pte_t pte)
+static inline pgprot_t pte_pgprot(pte_t pte)
{
- return __pgprot(pte_val(pte)) & PAGE_PROT_BITS;
+ return __pgprot(pte_val(pte) & PAGE_PROT_BITS);
}
/* Atomic PTE updates */
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 0966899d974..c4a029ccb4d 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -268,7 +268,7 @@ n:
* Loads the value of the constant expression 'expr' into register 'rn'
* using immediate instructions only. Use this when it's important not
* to reference other data (i.e. on ppc64 when the TOC pointer is not
- * valid).
+ * valid) and when 'expr' is a constant or absolute address.
*
* LOAD_REG_ADDR(rn, name)
* Loads the address of label 'name' into register 'rn'. Use this when
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h
index be980f4ee49..67453766bff 100644
--- a/arch/powerpc/include/asm/reg_booke.h
+++ b/arch/powerpc/include/asm/reg_booke.h
@@ -109,6 +109,7 @@
#define SPRN_EVPR 0x3D6 /* Exception Vector Prefix Register */
#define SPRN_L1CSR0 0x3F2 /* L1 Cache Control and Status Register 0 */
#define SPRN_L1CSR1 0x3F3 /* L1 Cache Control and Status Register 1 */
+#define SPRN_MMUCSR0 0x3F4 /* MMU Control and Status Register 0 */
#define SPRN_PIT 0x3DB /* Programmable Interval Timer */
#define SPRN_BUCSR 0x3F5 /* Branch Unit Control and Status */
#define SPRN_L2CSR0 0x3F9 /* L2 Data Cache Control and Status Register 0 */
@@ -410,6 +411,12 @@
#define L2CSR0_L2LOA 0x00000080 /* L2 Cache Lock Overflow Allocate */
#define L2CSR0_L2LO 0x00000020 /* L2 Cache Lock Overflow */
+/* Bit definitions for MMUCSR0 */
+#define MMUCSR0_TLB1FI 0x00000002 /* TLB1 Flash invalidate */
+#define MMUCSR0_TLB0FI 0x00000004 /* TLB0 Flash invalidate */
+#define MMUCSR0_TLB2FI 0x00000040 /* TLB2 Flash invalidate */
+#define MMUCSR0_TLB3FI 0x00000020 /* TLB3 Flash invalidate */
+
/* Bit definitions for SGR. */
#define SGR_NORMAL 0 /* Speculative fetching allowed. */
#define SGR_GUARDED 1 /* Speculative fetching disallowed. */
diff --git a/arch/powerpc/include/asm/sections.h b/arch/powerpc/include/asm/sections.h
index 07956f3e784..6fbce725c71 100644
--- a/arch/powerpc/include/asm/sections.h
+++ b/arch/powerpc/include/asm/sections.h
@@ -18,6 +18,12 @@ static inline int in_kernel_text(unsigned long addr)
return 0;
}
+static inline int overlaps_kernel_text(unsigned long start, unsigned long end)
+{
+ return start < (unsigned long)__init_end &&
+ (unsigned long)_stext < end;
+}
+
#undef dereference_function_descriptor
static inline void *dereference_function_descriptor(void *ptr)
{
diff --git a/arch/powerpc/math-emu/sfp-machine.h b/arch/powerpc/include/asm/sfp-machine.h
index 4b17d83cfcd..ced34f1dc8f 100644
--- a/arch/powerpc/math-emu/sfp-machine.h
+++ b/arch/powerpc/include/asm/sfp-machine.h
@@ -79,27 +79,44 @@
* #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
*/
-#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
-#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
-#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
-#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
/* These macros define what NaN looks like. They're supposed to expand to
* a comma-separated set of 32bit unsigned ints that encode NaN.
*/
-#define _FP_NANFRAC_S _FP_QNANBIT_S
-#define _FP_NANFRAC_D _FP_QNANBIT_D, 0
-#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0
+#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S 0
+#define _FP_NANSIGN_D 0
+#define _FP_NANSIGN_Q 0
#define _FP_KEEPNANFRACP 1
+/* Exception flags. We use the bit positions of the appropriate bits
+ in the FPSCR, which also correspond to the FE_* bits. This makes
+ everything easier ;-). */
+#define FP_EX_INVALID (1 << (31 - 2))
+#define FP_EX_INVALID_SNAN EFLAG_VXSNAN
+#define FP_EX_INVALID_ISI EFLAG_VXISI
+#define FP_EX_INVALID_IDI EFLAG_VXIDI
+#define FP_EX_INVALID_ZDZ EFLAG_VXZDZ
+#define FP_EX_INVALID_IMZ EFLAG_VXIMZ
+#define FP_EX_OVERFLOW (1 << (31 - 3))
+#define FP_EX_UNDERFLOW (1 << (31 - 4))
+#define FP_EX_DIVZERO (1 << (31 - 5))
+#define FP_EX_INEXACT (1 << (31 - 6))
+
/* This macro appears to be called when both X and Y are NaNs, and
* has to choose one and copy it to R. i386 goes for the larger of the
* two, sparc64 just picks Y. I don't understand this at all so I'll
* go with sparc64 because it's shorter :-> -- PMM
*/
-#define _FP_CHOOSENAN(fs, wc, R, X, Y) \
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
do { \
R##_s = Y##_s; \
_FP_FRAC_COPY_##wc(R,Y); \
@@ -107,62 +124,6 @@
} while (0)
-extern void fp_unpack_d(long *, unsigned long *, unsigned long *,
- long *, long *, void *);
-extern int fp_pack_d(void *, long, unsigned long, unsigned long, long, long);
-extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
-
-#define __FP_UNPACK_RAW_1(fs, X, val) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- X##_f = _flo->bits.frac; \
- X##_e = _flo->bits.exp; \
- X##_s = _flo->bits.sign; \
- } while (0)
-
-#define __FP_UNPACK_RAW_2(fs, X, val) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- X##_f0 = _flo->bits.frac0; \
- X##_f1 = _flo->bits.frac1; \
- X##_e = _flo->bits.exp; \
- X##_s = _flo->bits.sign; \
- } while (0)
-
-#define __FP_UNPACK_S(X,val) \
- do { \
- __FP_UNPACK_RAW_1(S,X,val); \
- _FP_UNPACK_CANONICAL(S,1,X); \
- } while (0)
-
-#define __FP_UNPACK_D(X,val) \
- fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val)
-
-#define __FP_PACK_RAW_1(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac = X##_f; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
-#define __FP_PACK_RAW_2(fs, val, X) \
- do { \
- union _FP_UNION_##fs *_flo = \
- (union _FP_UNION_##fs *)val; \
- \
- _flo->bits.frac0 = X##_f0; \
- _flo->bits.frac1 = X##_f1; \
- _flo->bits.exp = X##_e; \
- _flo->bits.sign = X##_s; \
- } while (0)
-
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -182,15 +143,30 @@ extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
#define __FP_PACK_S(val,X) \
({ int __exc = _FP_PACK_CANONICAL(S,1,X); \
if(!__exc || !__FPU_TRAP_P(__exc)) \
- __FP_PACK_RAW_1(S,val,X); \
+ _FP_PACK_RAW_1_P(S,val,X); \
__exc; \
})
#define __FP_PACK_D(val,X) \
- fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
-
-#define __FP_PACK_DS(val,X) \
- fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
+ do { \
+ _FP_PACK_CANONICAL(D, 2, X); \
+ if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) \
+ _FP_PACK_RAW_2_P(D, val, X); \
+ } while (0)
+
+#define __FP_PACK_DS(val,X) \
+ do { \
+ FP_DECL_S(__X); \
+ FP_CONV(S, D, 1, 2, __X, X); \
+ _FP_PACK_CANONICAL(S, 1, __X); \
+ if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) { \
+ _FP_UNPACK_CANONICAL(S, 1, __X); \
+ FP_CONV(D, S, 2, 1, X, __X); \
+ _FP_PACK_CANONICAL(D, 2, X); \
+ if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) \
+ _FP_PACK_RAW_2_P(D, val, X); \
+ } \
+ } while (0)
/* Obtain the current rounding mode. */
#define FP_ROUNDMODE \
diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
index 4d28e1e4521..1866cec4f96 100644
--- a/arch/powerpc/include/asm/smp.h
+++ b/arch/powerpc/include/asm/smp.h
@@ -56,9 +56,16 @@ extern int smp_hw_index[];
#define raw_smp_processor_id() (current_thread_info()->cpu)
#define hard_smp_processor_id() (smp_hw_index[smp_processor_id()])
-#define get_hard_smp_processor_id(cpu) (smp_hw_index[(cpu)])
-#define set_hard_smp_processor_id(cpu, phys)\
- (smp_hw_index[(cpu)] = (phys))
+
+static inline int get_hard_smp_processor_id(int cpu)
+{
+ return smp_hw_index[cpu];
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+ smp_hw_index[cpu] = phys;
+}
#endif
DECLARE_PER_CPU(cpumask_t, cpu_sibling_map);
@@ -86,15 +93,21 @@ extern void __cpu_die(unsigned int cpu);
#else
/* for UP */
-#define hard_smp_processor_id() 0
+#define hard_smp_processor_id() get_hard_smp_processor_id(0)
#define smp_setup_cpu_maps()
#endif /* CONFIG_SMP */
#ifdef CONFIG_PPC64
-#define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id)
-#define set_hard_smp_processor_id(CPU, VAL) \
- do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0)
+static inline int get_hard_smp_processor_id(int cpu)
+{
+ return paca[cpu].hw_cpu_id;
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+ paca[cpu].hw_cpu_id = phys;
+}
extern void smp_release_cpus(void);
@@ -102,10 +115,17 @@ extern void smp_release_cpus(void);
/* 32-bit */
#ifndef CONFIG_SMP
extern int boot_cpuid_phys;
-#define get_hard_smp_processor_id(cpu) boot_cpuid_phys
-#define set_hard_smp_processor_id(cpu, phys)
-#endif
-#endif
+static inline int get_hard_smp_processor_id(int cpu)
+{
+ return boot_cpuid_phys;
+}
+
+static inline void set_hard_smp_processor_id(int cpu, int phys)
+{
+ boot_cpuid_phys = phys;
+}
+#endif /* !CONFIG_SMP */
+#endif /* !CONFIG_PPC64 */
extern int smt_enabled_at_boot;
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index f6cc7a43b4f..803def23665 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -32,7 +32,7 @@ COMPAT_SYS_SPU(stime)
COMPAT_SYS(ptrace)
SYSCALL_SPU(alarm)
OLDSYS(fstat)
-COMPAT_SYS(pause)
+SYSCALL(pause)
COMPAT_SYS(utime)
SYSCALL(ni_syscall)
SYSCALL(ni_syscall)
diff --git a/arch/powerpc/include/asm/tlbflush.h b/arch/powerpc/include/asm/tlbflush.h
index 361cd5c7a32..a2c6bfd85fb 100644
--- a/arch/powerpc/include/asm/tlbflush.h
+++ b/arch/powerpc/include/asm/tlbflush.h
@@ -29,6 +29,9 @@
#include <linux/mm.h>
extern void _tlbie(unsigned long address, unsigned int pid);
+extern void _tlbil_all(void);
+extern void _tlbil_pid(unsigned int pid);
+extern void _tlbil_va(unsigned long address, unsigned int pid);
#if defined(CONFIG_40x) || defined(CONFIG_8xx)
#define _tlbia() asm volatile ("tlbia; sync" : : : "memory")
@@ -38,31 +41,31 @@ extern void _tlbia(void);
static inline void flush_tlb_mm(struct mm_struct *mm)
{
- _tlbia();
+ _tlbil_pid(mm->context.id);
}
static inline void flush_tlb_page(struct vm_area_struct *vma,
unsigned long vmaddr)
{
- _tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
+ _tlbil_va(vmaddr, vma ? vma->vm_mm->context.id : 0);
}
static inline void flush_tlb_page_nohash(struct vm_area_struct *vma,
unsigned long vmaddr)
{
- _tlbie(vmaddr, vma ? vma->vm_mm->context.id : 0);
+ flush_tlb_page(vma, vmaddr);
}
static inline void flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end)
{
- _tlbia();
+ _tlbil_pid(vma->vm_mm->context.id);
}
static inline void flush_tlb_kernel_range(unsigned long start,
unsigned long end)
{
- _tlbia();
+ _tlbil_pid(0);
}
#elif defined(CONFIG_PPC32)
diff --git a/arch/powerpc/include/asm/types.h b/arch/powerpc/include/asm/types.h
index d3374bc865b..a9a9262e84a 100644
--- a/arch/powerpc/include/asm/types.h
+++ b/arch/powerpc/include/asm/types.h
@@ -55,7 +55,7 @@ typedef u64 phys_addr_t;
typedef u32 phys_addr_t;
#endif
-#ifdef __powerpc64__
+#if defined(__powerpc64__) || defined(CONFIG_PHYS_64BIT)
typedef u64 dma_addr_t;
#else
typedef u32 dma_addr_t;
diff --git a/arch/powerpc/kernel/.gitignore b/arch/powerpc/kernel/.gitignore
new file mode 100644
index 00000000000..c5f676c3c22
--- /dev/null
+++ b/arch/powerpc/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 946daea780f..fdb58253fa5 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -28,13 +28,14 @@ endif
obj-y := cputable.o ptrace.o syscalls.o \
irq.o align.o signal_32.o pmc.o vdso.o \
init_task.o process.o systbl.o idle.o \
- signal.o
+ signal.o sysfs.o
obj-y += vdso32/
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
signal_64.o ptrace32.o \
paca.o cpu_setup_ppc970.o \
cpu_setup_pa6t.o \
- firmware.o sysfs.o nvram_64.o
+ firmware.o nvram_64.o
+obj64-$(CONFIG_RELOCATABLE) += reloc_64.o
obj-$(CONFIG_PPC64) += vdso64/
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
obj-$(CONFIG_PPC_970_NAP) += idle_power4.o
@@ -69,10 +70,10 @@ extra-$(CONFIG_8xx) := head_8xx.o
extra-y += vmlinux.lds
obj-y += time.o prom.o traps.o setup-common.o \
- udbg.o misc.o io.o \
+ udbg.o misc.o io.o dma.o \
misc_$(CONFIG_WORD_SIZE).o
obj-$(CONFIG_PPC32) += entry_32.o setup_32.o
-obj-$(CONFIG_PPC64) += dma_64.o iommu.o
+obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
obj-$(CONFIG_MODULES) += ppc_ksyms.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 92768d3006f..09febc58258 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -122,6 +122,8 @@ int main(void)
DEFINE(PACASTABRR, offsetof(struct paca_struct, stab_rr));
DEFINE(PACAR1, offsetof(struct paca_struct, saved_r1));
DEFINE(PACATOC, offsetof(struct paca_struct, kernel_toc));
+ DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase));
+ DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr));
DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled));
DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled));
DEFINE(PACASLBCACHE, offsetof(struct paca_struct, slb_cache));
@@ -350,6 +352,7 @@ int main(void)
#endif
DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE);
+ DEFINE(PTE_SIZE, sizeof(pte_t));
#ifdef CONFIG_KVM
DEFINE(TLBE_BYTES, sizeof(struct tlbe));
diff --git a/arch/powerpc/kernel/btext.c b/arch/powerpc/kernel/btext.c
index d8f0329b134..26e58630ed7 100644
--- a/arch/powerpc/kernel/btext.c
+++ b/arch/powerpc/kernel/btext.c
@@ -442,28 +442,26 @@ void btext_drawtext(const char *c, unsigned int len)
void btext_drawhex(unsigned long v)
{
- char *hex_table = "0123456789abcdef";
-
if (!boot_text_mapped)
return;
#ifdef CONFIG_PPC64
- btext_drawchar(hex_table[(v >> 60) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 56) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 52) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 48) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 44) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 40) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 36) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 32) & 0x0000000FUL]);
+ btext_drawchar(hex_asc_hi(v >> 56));
+ btext_drawchar(hex_asc_lo(v >> 56));
+ btext_drawchar(hex_asc_hi(v >> 48));
+ btext_drawchar(hex_asc_lo(v >> 48));
+ btext_drawchar(hex_asc_hi(v >> 40));
+ btext_drawchar(hex_asc_lo(v >> 40));
+ btext_drawchar(hex_asc_hi(v >> 32));
+ btext_drawchar(hex_asc_lo(v >> 32));
#endif
- btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]);
- btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]);
+ btext_drawchar(hex_asc_hi(v >> 24));
+ btext_drawchar(hex_asc_lo(v >> 24));
+ btext_drawchar(hex_asc_hi(v >> 16));
+ btext_drawchar(hex_asc_lo(v >> 16));
+ btext_drawchar(hex_asc_hi(v >> 8));
+ btext_drawchar(hex_asc_lo(v >> 8));
+ btext_drawchar(hex_asc_hi(v));
+ btext_drawchar(hex_asc_lo(v));
btext_drawchar(' ');
}
diff --git a/arch/powerpc/kernel/cpu_setup_ppc970.S b/arch/powerpc/kernel/cpu_setup_ppc970.S
index bf118c38575..27f2507279d 100644
--- a/arch/powerpc/kernel/cpu_setup_ppc970.S
+++ b/arch/powerpc/kernel/cpu_setup_ppc970.S
@@ -110,7 +110,7 @@ load_hids:
isync
/* Save away cpu state */
- LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+ LOAD_REG_ADDR(r5,cpu_state_storage)
/* Save HID0,1,4 and 5 */
mfspr r3,SPRN_HID0
@@ -134,7 +134,7 @@ _GLOBAL(__restore_cpu_ppc970)
rldicl. r0,r0,4,63
beqlr
- LOAD_REG_IMMEDIATE(r5,cpu_state_storage)
+ LOAD_REG_ADDR(r5,cpu_state_storage)
/* Before accessing memory, we make sure rm_ci is clear */
li r0,0
mfspr r3,SPRN_HID4
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 25c273c761d..e70d0483fb4 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -610,6 +610,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750cx,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -623,6 +624,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750cx,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -636,6 +638,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750cx,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -649,6 +652,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -662,6 +666,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -675,6 +680,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -688,6 +694,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -701,6 +708,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750fx,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -714,6 +722,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750fx,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -727,6 +736,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_IBM,
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
@@ -741,6 +751,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_7400,
.machine_check = machine_check_generic,
.platform = "ppc7400",
@@ -755,6 +766,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_7400,
.machine_check = machine_check_generic,
.platform = "ppc7400",
@@ -769,6 +781,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 4,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_7410,
.machine_check = machine_check_generic,
.platform = "ppc7400",
@@ -783,6 +796,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -799,6 +813,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -815,6 +830,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -831,6 +847,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -847,6 +864,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -863,6 +881,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -879,6 +898,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -895,6 +915,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -910,6 +931,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -926,6 +948,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
@@ -942,6 +965,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
.icache_bsize = 32,
.dcache_bsize = 32,
.num_pmcs = 6,
+ .pmc_type = PPC_PMC_G4,
.cpu_setup = __setup_cpu_745x,
.oprofile_cpu_type = "ppc/7450",
.oprofile_type = PPC_OPROFILE_G4,
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma-iommu.c
index ae5708e3a31..49248f89ce2 100644
--- a/arch/powerpc/kernel/dma_64.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -2,14 +2,10 @@
* Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
*
* Provide default implementations of the DMA mapping callbacks for
- * directly mapped busses and busses using the iommu infrastructure
+ * busses using the iommu infrastructure
*/
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <asm/bug.h>
#include <asm/iommu.h>
-#include <asm/abs_addr.h>
/*
* Generic iommu implementation
@@ -24,7 +20,7 @@ static void *dma_iommu_alloc_coherent(struct device *dev, size_t size,
{
return iommu_alloc_coherent(dev, dev->archdata.dma_data, size,
dma_handle, device_to_mask(dev), flag,
- dev->archdata.numa_node);
+ dev_to_node(dev));
}
static void dma_iommu_free_coherent(struct device *dev, size_t size,
@@ -105,96 +101,3 @@ struct dma_mapping_ops dma_iommu_ops = {
.dma_supported = dma_iommu_dma_supported,
};
EXPORT_SYMBOL(dma_iommu_ops);
-
-/*
- * Generic direct DMA implementation
- *
- * This implementation supports a per-device offset that can be applied if
- * the address at which memory is visible to devices is not 0. Platform code
- * can set archdata.dma_data to an unsigned long holding the offset. By
- * default the offset is zero.
- */
-
-static unsigned long get_dma_direct_offset(struct device *dev)
-{
- return (unsigned long)dev->archdata.dma_data;
-}
-
-static void *dma_direct_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t flag)
-{
- struct page *page;
- void *ret;
- int node = dev->archdata.numa_node;
-
- page = alloc_pages_node(node, flag, get_order(size));
- if (page == NULL)
- return NULL;
- ret = page_address(page);
- memset(ret, 0, size);
- *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
-
- return ret;
-}
-
-static void dma_direct_free_coherent(struct device *dev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr,
- size_t size,
- enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- return virt_to_abs(ptr) + get_dma_direct_offset(dev);
-}
-
-static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr,
- size_t size,
- enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
-}
-
-static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
- int nents, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
- struct scatterlist *sg;
- int i;
-
- for_each_sg(sgl, sg, nents, i) {
- sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
- sg->dma_length = sg->length;
- }
-
- return nents;
-}
-
-static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
- int nents, enum dma_data_direction direction,
- struct dma_attrs *attrs)
-{
-}
-
-static int dma_direct_dma_supported(struct device *dev, u64 mask)
-{
- /* Could be improved to check for memory though it better be
- * done via some global so platforms can set the limit in case
- * they have limited DMA windows
- */
- return mask >= DMA_32BIT_MASK;
-}
-
-struct dma_mapping_ops dma_direct_ops = {
- .alloc_coherent = dma_direct_alloc_coherent,
- .free_coherent = dma_direct_free_coherent,
- .map_single = dma_direct_map_single,
- .unmap_single = dma_direct_unmap_single,
- .map_sg = dma_direct_map_sg,
- .unmap_sg = dma_direct_unmap_sg,
- .dma_supported = dma_direct_dma_supported,
-};
-EXPORT_SYMBOL(dma_direct_ops);
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
new file mode 100644
index 00000000000..1562daf8839
--- /dev/null
+++ b/arch/powerpc/kernel/dma.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corporation
+ *
+ * Provide default implementations of the DMA mapping callbacks for
+ * directly mapped busses.
+ */
+
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <asm/bug.h>
+#include <asm/abs_addr.h>
+
+/*
+ * Generic direct DMA implementation
+ *
+ * This implementation supports a per-device offset that can be applied if
+ * the address at which memory is visible to devices is not 0. Platform code
+ * can set archdata.dma_data to an unsigned long holding the offset. By
+ * default the offset is PCI_DRAM_OFFSET.
+ */
+
+static unsigned long get_dma_direct_offset(struct device *dev)
+{
+ if (dev)
+ return (unsigned long)dev->archdata.dma_data;
+
+ return PCI_DRAM_OFFSET;
+}
+
+void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag)
+{
+ void *ret;
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ ret = __dma_alloc_coherent(size, dma_handle, flag);
+ if (ret == NULL)
+ return NULL;
+ *dma_handle += get_dma_direct_offset(dev);
+ return ret;
+#else
+ struct page *page;
+ int node = dev_to_node(dev);
+
+ /* ignore region specifiers */
+ flag &= ~(__GFP_HIGHMEM);
+
+ page = alloc_pages_node(node, flag, get_order(size));
+ if (page == NULL)
+ return NULL;
+ ret = page_address(page);
+ memset(ret, 0, size);
+ *dma_handle = virt_to_abs(ret) + get_dma_direct_offset(dev);
+
+ return ret;
+#endif
+}
+
+void dma_direct_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+#ifdef CONFIG_NOT_COHERENT_CACHE
+ __dma_free_coherent(size, vaddr);
+#else
+ free_pages((unsigned long)vaddr, get_order(size));
+#endif
+}
+
+static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ struct scatterlist *sg;
+ int i;
+
+ for_each_sg(sgl, sg, nents, i) {
+ sg->dma_address = sg_phys(sg) + get_dma_direct_offset(dev);
+ sg->dma_length = sg->length;
+ }
+
+ return nents;
+}
+
+static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nents, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+}
+
+static int dma_direct_dma_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_PPC64
+ /* Could be improved to check for memory though it better be
+ * done via some global so platforms can set the limit in case
+ * they have limited DMA windows
+ */
+ return mask >= DMA_32BIT_MASK;
+#else
+ return 1;
+#endif
+}
+
+static inline dma_addr_t dma_direct_map_page(struct device *dev,
+ struct page *page,
+ unsigned long offset,
+ size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ BUG_ON(dir == DMA_NONE);
+ __dma_sync_page(page, offset, size, dir);
+ return page_to_phys(page) + offset + get_dma_direct_offset(dev);
+}
+
+static inline void dma_direct_unmap_page(struct device *dev,
+ dma_addr_t dma_address,
+ size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+}
+
+struct dma_mapping_ops dma_direct_ops = {
+ .alloc_coherent = dma_direct_alloc_coherent,
+ .free_coherent = dma_direct_free_coherent,
+ .map_sg = dma_direct_map_sg,
+ .unmap_sg = dma_direct_unmap_sg,
+ .dma_supported = dma_direct_dma_supported,
+ .map_page = dma_direct_map_page,
+ .unmap_page = dma_direct_unmap_page,
+};
+EXPORT_SYMBOL(dma_direct_ops);
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 2d802e97097..fd8b4bae9b0 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -512,31 +512,12 @@ _GLOBAL(ret_from_except_lite)
#endif
restore:
- ld r5,SOFTE(r1)
-#ifdef CONFIG_PPC_ISERIES
BEGIN_FW_FTR_SECTION
- cmpdi 0,r5,0
- beq 4f
- /* Check for pending interrupts (iSeries) */
- ld r3,PACALPPACAPTR(r13)
- ld r3,LPPACAANYINT(r3)
- cmpdi r3,0
- beq+ 4f /* skip do_IRQ if no interrupts */
-
- li r3,0
- stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */
-#ifdef CONFIG_TRACE_IRQFLAGS
- bl .trace_hardirqs_off
- mfmsr r10
-#endif
- ori r10,r10,MSR_EE
- mtmsrd r10 /* hard-enable again */
- addi r3,r1,STACK_FRAME_OVERHEAD
- bl .do_IRQ
- b .ret_from_except_lite /* loop back and handle more */
-4:
-END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
-#endif
+ ld r5,SOFTE(r1)
+FW_FTR_SECTION_ELSE
+ b iseries_check_pending_irqs
+ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES)
+2:
TRACE_AND_RESTORE_IRQ(r5);
/* extract EE bit and use it to restore paca->hard_enabled */
@@ -592,6 +573,30 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
rfid
b . /* prevent speculative execution */
+iseries_check_pending_irqs:
+#ifdef CONFIG_PPC_ISERIES
+ ld r5,SOFTE(r1)
+ cmpdi 0,r5,0
+ beq 2b
+ /* Check for pending interrupts (iSeries) */
+ ld r3,PACALPPACAPTR(r13)
+ ld r3,LPPACAANYINT(r3)
+ cmpdi r3,0
+ beq+ 2b /* skip do_IRQ if no interrupts */
+
+ li r3,0
+ stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl .trace_hardirqs_off
+ mfmsr r10
+#endif
+ ori r10,r10,MSR_EE
+ mtmsrd r10 /* hard-enable again */
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .do_IRQ
+ b .ret_from_except_lite /* loop back and handle more */
+#endif
+
do_work:
#ifdef CONFIG_PREEMPT
andi. r0,r3,MSR_PR /* Returning to user mode? */
@@ -685,10 +690,6 @@ _GLOBAL(enter_rtas)
std r7,_DAR(r1)
mfdsisr r8
std r8,_DSISR(r1)
- mfsrr0 r9
- std r9,_SRR0(r1)
- mfsrr1 r10
- std r10,_SRR1(r1)
/* Temporary workaround to clear CR until RTAS can be modified to
* ignore all bits.
@@ -749,6 +750,10 @@ _STATIC(rtas_return_loc)
mfspr r4,SPRN_SPRG3 /* Get PACA */
clrldi r4,r4,2 /* convert to realmode address */
+ bcl 20,31,$+4
+0: mflr r3
+ ld r3,(1f-0b)(r3) /* get &.rtas_restore_regs */
+
mfmsr r6
li r0,MSR_RI
andc r6,r6,r0
@@ -756,7 +761,6 @@ _STATIC(rtas_return_loc)
mtmsrd r6
ld r1,PACAR1(r4) /* Restore our SP */
- LOAD_REG_IMMEDIATE(r3,.rtas_restore_regs)
ld r4,PACASAVEDMSR(r4) /* Restore our MSR */
mtspr SPRN_SRR0,r3
@@ -764,6 +768,9 @@ _STATIC(rtas_return_loc)
rfid
b . /* prevent speculative execution */
+ .align 3
+1: .llong .rtas_restore_regs
+
_STATIC(rtas_restore_regs)
/* relocation is on at this point */
REST_GPR(2, r1) /* Restore the TOC */
@@ -783,10 +790,6 @@ _STATIC(rtas_restore_regs)
mtdar r7
ld r8,_DSISR(r1)
mtdsisr r8
- ld r9,_SRR0(r1)
- mtsrr0 r9
- ld r10,_SRR1(r1)
- mtsrr1 r10
addi r1,r1,RTAS_FRAME_SIZE /* Unstack our frame */
ld r0,16(r1) /* get return address */
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index 8bb65751929..0c326823c6d 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -110,6 +110,12 @@ __start:
#ifdef CONFIG_PPC_MULTIPLATFORM
cmpwi 0,r5,0
beq 1f
+
+ /* find out where we are now */
+ bcl 20,31,$+4
+0: mflr r8 /* r8 = runtime addr here */
+ addis r8,r8,(_stext - 0b)@ha
+ addi r8,r8,(_stext - 0b)@l /* current runtime base addr */
bl prom_init
trap
#endif
@@ -369,13 +375,13 @@ i##n: \
DataAccess:
EXCEPTION_PROLOG
mfspr r10,SPRN_DSISR
+ stw r10,_DSISR(r11)
andis. r0,r10,0xa470 /* weird error? */
bne 1f /* if not, try to put a PTE */
mfspr r4,SPRN_DAR /* into the hash table */
rlwinm r3,r10,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */
bl hash_page
-1: stw r10,_DSISR(r11)
- mr r5,r10
+1: lwz r5,_DSISR(r11) /* get DSISR value */
mfspr r4,SPRN_DAR
EXC_XFER_EE_LITE(0x300, handle_page_fault)
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index cc8fb474d52..84856bee33a 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -82,7 +82,11 @@ END_FTR_SECTION(0, 1)
/* Catch branch to 0 in real mode */
trap
- /* Secondary processors spin on this value until it goes to 1. */
+ /* Secondary processors spin on this value until it becomes nonzero.
+ * When it does it contains the real address of the descriptor
+ * of the function that the cpu should jump to to continue
+ * initialization.
+ */
.globl __secondary_hold_spinloop
__secondary_hold_spinloop:
.llong 0x0
@@ -109,8 +113,11 @@ __secondary_hold_acknowledge:
* before the bulk of the kernel has been relocated. This code
* is relocated to physical address 0x60 before prom_init is run.
* All of it must fit below the first exception vector at 0x100.
+ * Use .globl here not _GLOBAL because we want __secondary_hold
+ * to be the actual text address, not a descriptor.
*/
-_GLOBAL(__secondary_hold)
+ .globl __secondary_hold
+__secondary_hold:
mfmsr r24
ori r24,r24,MSR_RI
mtmsrd r24 /* RI on */
@@ -121,16 +128,16 @@ _GLOBAL(__secondary_hold)
/* Tell the master cpu we're here */
/* Relocation is off & we are located at an address less */
/* than 0x100, so only need to grab low order offset. */
- std r24,__secondary_hold_acknowledge@l(0)
+ std r24,__secondary_hold_acknowledge-_stext(0)
sync
/* All secondary cpus wait here until told to start. */
-100: ld r4,__secondary_hold_spinloop@l(0)
- cmpdi 0,r4,1
- bne 100b
+100: ld r4,__secondary_hold_spinloop-_stext(0)
+ cmpdi 0,r4,0
+ beq 100b
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
- LOAD_REG_IMMEDIATE(r4, .generic_secondary_smp_init)
+ ld r4,0(r4) /* deref function descriptor */
mtctr r4
mr r3,r24
bctr
@@ -147,6 +154,10 @@ exception_marker:
/*
* This is the start of the interrupt handlers for pSeries
* This code runs with relocation off.
+ * Code from here to __end_interrupts gets copied down to real
+ * address 0x100 when we are running a relocatable kernel.
+ * Therefore any relative branches in this section must only
+ * branch to labels in this section.
*/
. = 0x100
.globl __start_interrupts
@@ -200,7 +211,20 @@ data_access_slb_pSeries:
mfspr r10,SPRN_SPRG1
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
- b .slb_miss_realmode /* Rel. branch works in real mode */
+#ifndef CONFIG_RELOCATABLE
+ b .slb_miss_realmode
+#else
+ /*
+ * We can't just use a direct branch to .slb_miss_realmode
+ * because the distance from here to there depends on where
+ * the kernel ends up being put.
+ */
+ mfctr r11
+ ld r10,PACAKBASE(r13)
+ LOAD_HANDLER(r10, .slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
STD_EXCEPTION_PSERIES(0x400, instruction_access)
@@ -225,7 +249,15 @@ instruction_access_slb_pSeries:
mfspr r10,SPRN_SPRG1
std r10,PACA_EXSLB+EX_R13(r13)
mfspr r12,SPRN_SRR1 /* and SRR1 */
- b .slb_miss_realmode /* Rel. branch works in real mode */
+#ifndef CONFIG_RELOCATABLE
+ b .slb_miss_realmode
+#else
+ mfctr r11
+ ld r10,PACAKBASE(r13)
+ LOAD_HANDLER(r10, .slb_miss_realmode)
+ mtctr r10
+ bctr
+#endif
MASKABLE_EXCEPTION_PSERIES(0x500, hardware_interrupt)
STD_EXCEPTION_PSERIES(0x600, alignment)
@@ -244,14 +276,12 @@ BEGIN_FTR_SECTION
beq- 1f
END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)
mr r9,r13
- mfmsr r10
mfspr r13,SPRN_SPRG3
mfspr r11,SPRN_SRR0
- clrrdi r12,r13,32
- oris r12,r12,system_call_common@h
- ori r12,r12,system_call_common@l
+ ld r12,PACAKBASE(r13)
+ ld r10,PACAKMSR(r13)
+ LOAD_HANDLER(r12, system_call_entry)
mtspr SPRN_SRR0,r12
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI
mfspr r12,SPRN_SRR1
mtspr SPRN_SRR1,r10
rfid
@@ -325,16 +355,32 @@ do_stab_bolted_pSeries:
mfspr r12,SPRN_SPRG2
EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted)
+#ifdef CONFIG_PPC_PSERIES
+/*
+ * Vectors for the FWNMI option. Share common code.
+ */
+ .globl system_reset_fwnmi
+ .align 7
+system_reset_fwnmi:
+ HMT_MEDIUM
+ mtspr SPRN_SPRG1,r13 /* save r13 */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
+
+ .globl machine_check_fwnmi
+ .align 7
+machine_check_fwnmi:
+ HMT_MEDIUM
+ mtspr SPRN_SPRG1,r13 /* save r13 */
+ EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
+
+#endif /* CONFIG_PPC_PSERIES */
+
+#ifdef __DISABLED__
/*
- * We have some room here we use that to put
- * the peries slb miss user trampoline code so it's reasonably
- * away from slb_miss_user_common to avoid problems with rfid
- *
* This is used for when the SLB miss handler has to go virtual,
* which doesn't happen for now anymore but will once we re-implement
* dynamic VSIDs for shared page tables
*/
-#ifdef __DISABLED__
slb_miss_user_pseries:
std r10,PACA_EXGEN+EX_R10(r13)
std r11,PACA_EXGEN+EX_R11(r13)
@@ -357,25 +403,17 @@ slb_miss_user_pseries:
b . /* prevent spec. execution */
#endif /* __DISABLED__ */
-#ifdef CONFIG_PPC_PSERIES
+ .align 7
+ .globl __end_interrupts
+__end_interrupts:
+
/*
- * Vectors for the FWNMI option. Share common code.
+ * Code from here down to __end_handlers is invoked from the
+ * exception prologs above. Because the prologs assemble the
+ * addresses of these handlers using the LOAD_HANDLER macro,
+ * which uses an addi instruction, these handlers must be in
+ * the first 32k of the kernel image.
*/
- .globl system_reset_fwnmi
- .align 7
-system_reset_fwnmi:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXGEN, system_reset_common)
-
- .globl machine_check_fwnmi
- .align 7
-machine_check_fwnmi:
- HMT_MEDIUM
- mtspr SPRN_SPRG1,r13 /* save r13 */
- EXCEPTION_PROLOG_PSERIES_FORCE_64BIT(PACA_EXMC, machine_check_common)
-
-#endif /* CONFIG_PPC_PSERIES */
/*** Common interrupt handlers ***/
@@ -414,6 +452,10 @@ machine_check_common:
STD_EXCEPTION_COMMON(0x1800, cbe_thermal, .cbe_thermal_exception)
#endif /* CONFIG_CBE_RAS */
+ .align 7
+system_call_entry:
+ b system_call_common
+
/*
* Here we have detected that the kernel stack pointer is bad.
* R9 contains the saved CR, r13 points to the paca,
@@ -457,65 +499,6 @@ bad_stack:
b 1b
/*
- * Return from an exception with minimal checks.
- * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
- * If interrupts have been enabled, or anything has been
- * done that might have changed the scheduling status of
- * any task or sent any task a signal, you should use
- * ret_from_except or ret_from_except_lite instead of this.
- */
-fast_exc_return_irq: /* restores irq state too */
- ld r3,SOFTE(r1)
- TRACE_AND_RESTORE_IRQ(r3);
- ld r12,_MSR(r1)
- rldicl r4,r12,49,63 /* get MSR_EE to LSB */
- stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */
- b 1f
-
- .globl fast_exception_return
-fast_exception_return:
- ld r12,_MSR(r1)
-1: ld r11,_NIP(r1)
- andi. r3,r12,MSR_RI /* check if RI is set */
- beq- unrecov_fer
-
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- andi. r3,r12,MSR_PR
- beq 2f
- ACCOUNT_CPU_USER_EXIT(r3, r4)
-2:
-#endif
-
- ld r3,_CCR(r1)
- ld r4,_LINK(r1)
- ld r5,_CTR(r1)
- ld r6,_XER(r1)
- mtcr r3
- mtlr r4
- mtctr r5
- mtxer r6
- REST_GPR(0, r1)
- REST_8GPRS(2, r1)
-
- mfmsr r10
- rldicl r10,r10,48,1 /* clear EE */
- rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */
- mtmsrd r10,1
-
- mtspr SPRN_SRR1,r12
- mtspr SPRN_SRR0,r11
- REST_4GPRS(10, r1)
- ld r1,GPR1(r1)
- rfid
- b . /* prevent speculative execution */
-
-unrecov_fer:
- bl .save_nvgprs
-1: addi r3,r1,STACK_FRAME_OVERHEAD
- bl .unrecoverable_exception
- b 1b
-
-/*
* Here r13 points to the paca, r9 contains the saved CR,
* SRR0 and SRR1 are saved in r11 and r12,
* r9 - r13 are saved in paca->exgen.
@@ -616,6 +599,9 @@ unrecov_user_slb:
*/
_GLOBAL(slb_miss_realmode)
mflr r10
+#ifdef CONFIG_RELOCATABLE
+ mtctr r11
+#endif
stw r9,PACA_EXSLB+EX_CCR(r13) /* save CR in exc. frame */
std r10,PACA_EXSLB+EX_LR(r13) /* save LR */
@@ -666,11 +652,10 @@ BEGIN_FW_FTR_SECTION
END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif /* CONFIG_PPC_ISERIES */
mfspr r11,SPRN_SRR0
- clrrdi r10,r13,32
+ ld r10,PACAKBASE(r13)
LOAD_HANDLER(r10,unrecov_slb)
mtspr SPRN_SRR0,r10
- mfmsr r10
- ori r10,r10,MSR_IR|MSR_DR|MSR_RI
+ ld r10,PACAKMSR(r13)
mtspr SPRN_SRR1,r10
rfid
b .
@@ -766,6 +751,85 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
bl .altivec_unavailable_exception
b .ret_from_except
+ .align 7
+ .globl vsx_unavailable_common
+vsx_unavailable_common:
+ EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+ bne .load_up_vsx
+1:
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ ENABLE_INTS
+ bl .vsx_unavailable_exception
+ b .ret_from_except
+
+ .align 7
+ .globl __end_handlers
+__end_handlers:
+
+/*
+ * Return from an exception with minimal checks.
+ * The caller is assumed to have done EXCEPTION_PROLOG_COMMON.
+ * If interrupts have been enabled, or anything has been
+ * done that might have changed the scheduling status of
+ * any task or sent any task a signal, you should use
+ * ret_from_except or ret_from_except_lite instead of this.
+ */
+fast_exc_return_irq: /* restores irq state too */
+ ld r3,SOFTE(r1)
+ TRACE_AND_RESTORE_IRQ(r3);
+ ld r12,_MSR(r1)
+ rldicl r4,r12,49,63 /* get MSR_EE to LSB */
+ stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */
+ b 1f
+
+ .globl fast_exception_return
+fast_exception_return:
+ ld r12,_MSR(r1)
+1: ld r11,_NIP(r1)
+ andi. r3,r12,MSR_RI /* check if RI is set */
+ beq- unrecov_fer
+
+#ifdef CONFIG_VIRT_CPU_ACCOUNTING
+ andi. r3,r12,MSR_PR
+ beq 2f
+ ACCOUNT_CPU_USER_EXIT(r3, r4)
+2:
+#endif
+
+ ld r3,_CCR(r1)
+ ld r4,_LINK(r1)
+ ld r5,_CTR(r1)
+ ld r6,_XER(r1)
+ mtcr r3
+ mtlr r4
+ mtctr r5
+ mtxer r6
+ REST_GPR(0, r1)
+ REST_8GPRS(2, r1)
+
+ mfmsr r10
+ rldicl r10,r10,48,1 /* clear EE */
+ rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */
+ mtmsrd r10,1
+
+ mtspr SPRN_SRR1,r12
+ mtspr SPRN_SRR0,r11
+ REST_4GPRS(10, r1)
+ ld r1,GPR1(r1)
+ rfid
+ b . /* prevent speculative execution */
+
+unrecov_fer:
+ bl .save_nvgprs
+1: addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .unrecoverable_exception
+ b 1b
+
#ifdef CONFIG_ALTIVEC
/*
* load_up_altivec(unused, unused, tsk)
@@ -840,22 +904,6 @@ _STATIC(load_up_altivec)
blr
#endif /* CONFIG_ALTIVEC */
- .align 7
- .globl vsx_unavailable_common
-vsx_unavailable_common:
- EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN)
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
- bne .load_up_vsx
-1:
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
- bl .save_nvgprs
- addi r3,r1,STACK_FRAME_OVERHEAD
- ENABLE_INTS
- bl .vsx_unavailable_exception
- b .ret_from_except
-
#ifdef CONFIG_VSX
/*
* load_up_vsx(unused, unused, tsk)
@@ -1175,11 +1223,14 @@ _GLOBAL(generic_secondary_smp_init)
/* turn on 64-bit mode */
bl .enable_64b_mode
+ /* get the TOC pointer (real address) */
+ bl .relative_toc
+
/* Set up a paca value for this processor. Since we have the
* physical cpu id in r24, we need to search the pacas to find
* which logical id maps to our physical one.
*/
- LOAD_REG_IMMEDIATE(r13, paca) /* Get base vaddr of paca array */
+ LOAD_REG_ADDR(r13, paca) /* Get base vaddr of paca array */
li r5,0 /* logical cpu id */
1: lhz r6,PACAHWCPUID(r13) /* Load HW procid from paca */
cmpw r6,r24 /* Compare to our id */
@@ -1208,7 +1259,7 @@ _GLOBAL(generic_secondary_smp_init)
sync /* order paca.run and cur_cpu_spec */
/* See if we need to call a cpu state restore handler */
- LOAD_REG_IMMEDIATE(r23, cur_cpu_spec)
+ LOAD_REG_ADDR(r23, cur_cpu_spec)
ld r23,0(r23)
ld r23,CPU_SPEC_RESTORE(r23)
cmpdi 0,r23,0
@@ -1224,10 +1275,15 @@ _GLOBAL(generic_secondary_smp_init)
b __secondary_start
#endif
+/*
+ * Turn the MMU off.
+ * Assumes we're mapped EA == RA if the MMU is on.
+ */
_STATIC(__mmu_off)
mfmsr r3
andi. r0,r3,MSR_IR|MSR_DR
beqlr
+ mflr r4
andc r3,r3,r0
mtspr SPRN_SRR0,r4
mtspr SPRN_SRR1,r3
@@ -1248,6 +1304,18 @@ _STATIC(__mmu_off)
*
*/
_GLOBAL(__start_initialization_multiplatform)
+ /* Make sure we are running in 64 bits mode */
+ bl .enable_64b_mode
+
+ /* Get TOC pointer (current runtime address) */
+ bl .relative_toc
+
+ /* find out where we are now */
+ bcl 20,31,$+4
+0: mflr r26 /* r26 = runtime addr here */
+ addis r26,r26,(_stext - 0b)@ha
+ addi r26,r26,(_stext - 0b)@l /* current runtime base addr */
+
/*
* Are we booted from a PROM Of-type client-interface ?
*/
@@ -1259,9 +1327,6 @@ _GLOBAL(__start_initialization_multiplatform)
mr r31,r3
mr r30,r4
- /* Make sure we are running in 64 bits mode */
- bl .enable_64b_mode
-
/* Setup some critical 970 SPRs before switching MMU off */
mfspr r0,SPRN_PVR
srwi r0,r0,16
@@ -1276,9 +1341,7 @@ _GLOBAL(__start_initialization_multiplatform)
1: bl .__cpu_preinit_ppc970
2:
- /* Switch off MMU if not already */
- LOAD_REG_IMMEDIATE(r4, .__after_prom_start - KERNELBASE)
- add r4,r4,r30
+ /* Switch off MMU if not already off */
bl .__mmu_off
b .__after_prom_start
@@ -1293,22 +1356,15 @@ _INIT_STATIC(__boot_from_prom)
/*
* Align the stack to 16-byte boundary
* Depending on the size and layout of the ELF sections in the initial
- * boot binary, the stack pointer will be unalignet on PowerMac
+ * boot binary, the stack pointer may be unaligned on PowerMac
*/
rldicr r1,r1,0,59
- /* Make sure we are running in 64 bits mode */
- bl .enable_64b_mode
-
- /* put a relocation offset into r3 */
- bl .reloc_offset
-
- LOAD_REG_IMMEDIATE(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
-
- /* Relocate the TOC from a virt addr to a real addr */
- add r2,r2,r3
+#ifdef CONFIG_RELOCATABLE
+ /* Relocate code for where we are now */
+ mr r3,r26
+ bl .relocate
+#endif
/* Restore parameters */
mr r3,r31
@@ -1318,60 +1374,51 @@ _INIT_STATIC(__boot_from_prom)
mr r7,r27
/* Do all of the interaction with OF client interface */
+ mr r8,r26
bl .prom_init
/* We never return */
trap
_STATIC(__after_prom_start)
+#ifdef CONFIG_RELOCATABLE
+ /* process relocations for the final address of the kernel */
+ lis r25,PAGE_OFFSET@highest /* compute virtual base of kernel */
+ sldi r25,r25,32
+ mr r3,r25
+ bl .relocate
+#endif
/*
- * We need to run with __start at physical address PHYSICAL_START.
+ * We need to run with _stext at physical address PHYSICAL_START.
* This will leave some code in the first 256B of
* real memory, which are reserved for software use.
- * The remainder of the first page is loaded with the fixed
- * interrupt vectors. The next two pages are filled with
- * unknown exception placeholders.
*
* Note: This process overwrites the OF exception vectors.
- * r26 == relocation offset
- * r27 == KERNELBASE
*/
- bl .reloc_offset
- mr r26,r3
- LOAD_REG_IMMEDIATE(r27, KERNELBASE)
-
- LOAD_REG_IMMEDIATE(r3, PHYSICAL_START) /* target addr */
-
- // XXX FIXME: Use phys returned by OF (r30)
- add r4,r27,r26 /* source addr */
- /* current address of _start */
- /* i.e. where we are running */
- /* the source addr */
-
- cmpdi r4,0 /* In some cases the loader may */
- bne 1f
- b .start_here_multiplatform /* have already put us at zero */
- /* so we can skip the copy. */
-1: LOAD_REG_IMMEDIATE(r5,copy_to_here) /* # bytes of memory to copy */
- sub r5,r5,r27
-
+ li r3,0 /* target addr */
+ mr. r4,r26 /* In some cases the loader may */
+ beq 9f /* have already put us at zero */
+ lis r5,(copy_to_here - _stext)@ha
+ addi r5,r5,(copy_to_here - _stext)@l /* # bytes of memory to copy */
li r6,0x100 /* Start offset, the first 0x100 */
/* bytes were copied earlier. */
bl .copy_and_flush /* copy the first n bytes */
/* this includes the code being */
/* executed here. */
-
- LOAD_REG_IMMEDIATE(r0, 4f) /* Jump to the copy of this code */
- mtctr r0 /* that we just made/relocated */
+ addis r8,r3,(4f - _stext)@ha /* Jump to the copy of this code */
+ addi r8,r8,(4f - _stext)@l /* that we just made */
+ mtctr r8
bctr
-4: LOAD_REG_IMMEDIATE(r5,klimit)
- add r5,r5,r26
- ld r5,0(r5) /* get the value of klimit */
- sub r5,r5,r27
+4: /* Now copy the rest of the kernel up to _end */
+ addis r5,r26,(p_end - _stext)@ha
+ ld r5,(p_end - _stext)@l(r5) /* get _end */
bl .copy_and_flush /* copy the rest */
- b .start_here_multiplatform
+
+9: b .start_here_multiplatform
+
+p_end: .llong _end - _stext
/*
* Copy routine used to copy the kernel to start at physical address 0
@@ -1436,6 +1483,9 @@ _GLOBAL(pmac_secondary_start)
/* turn on 64-bit mode */
bl .enable_64b_mode
+ /* get TOC pointer (real address) */
+ bl .relative_toc
+
/* Copy some CPU settings from CPU 0 */
bl .__restore_cpu_ppc970
@@ -1445,10 +1495,10 @@ _GLOBAL(pmac_secondary_start)
mtmsrd r3 /* RI on */
/* Set up a paca value for this processor. */
- LOAD_REG_IMMEDIATE(r4, paca) /* Get base vaddr of paca array */
- mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
+ LOAD_REG_ADDR(r4,paca) /* Get base vaddr of paca array */
+ mulli r13,r24,PACA_SIZE /* Calculate vaddr of right paca */
add r13,r13,r4 /* for this processor. */
- mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
+ mtspr SPRN_SPRG3,r13 /* Save vaddr of paca in SPRG3 */
/* Create a temp kernel stack for use before relocation is on. */
ld r1,PACAEMERGSP(r13)
@@ -1476,9 +1526,6 @@ __secondary_start:
/* Set thread priority to MEDIUM */
HMT_MEDIUM
- /* Load TOC */
- ld r2,PACATOC(r13)
-
/* Do early setup for that CPU (stab, slb, hash table pointer) */
bl .early_setup_secondary
@@ -1515,9 +1562,11 @@ END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
/*
* Running with relocation on at this point. All we want to do is
- * zero the stack back-chain pointer before going into C code.
+ * zero the stack back-chain pointer and get the TOC virtual address
+ * before going into C code.
*/
_GLOBAL(start_secondary_prolog)
+ ld r2,PACATOC(r13)
li r3,0
std r3,0(r1) /* Zero the stack frame pointer */
bl .start_secondary
@@ -1529,34 +1578,46 @@ _GLOBAL(start_secondary_prolog)
*/
_GLOBAL(enable_64b_mode)
mfmsr r11 /* grab the current MSR */
- li r12,1
- rldicr r12,r12,MSR_SF_LG,(63-MSR_SF_LG)
- or r11,r11,r12
- li r12,1
- rldicr r12,r12,MSR_ISF_LG,(63-MSR_ISF_LG)
+ li r12,(MSR_SF | MSR_ISF)@highest
+ sldi r12,r12,48
or r11,r11,r12
mtmsrd r11
isync
blr
/*
+ * This puts the TOC pointer into r2, offset by 0x8000 (as expected
+ * by the toolchain). It computes the correct value for wherever we
+ * are running at the moment, using position-independent code.
+ */
+_GLOBAL(relative_toc)
+ mflr r0
+ bcl 20,31,$+4
+0: mflr r9
+ ld r2,(p_toc - 0b)(r9)
+ add r2,r2,r9
+ mtlr r0
+ blr
+
+p_toc: .llong __toc_start + 0x8000 - 0b
+
+/*
* This is where the main kernel code starts.
*/
_INIT_STATIC(start_here_multiplatform)
- /* get a new offset, now that the kernel has moved. */
- bl .reloc_offset
- mr r26,r3
+ /* set up the TOC (real address) */
+ bl .relative_toc
/* Clear out the BSS. It may have been done in prom_init,
* already but that's irrelevant since prom_init will soon
* be detached from the kernel completely. Besides, we need
* to clear it now for kexec-style entry.
*/
- LOAD_REG_IMMEDIATE(r11,__bss_stop)
- LOAD_REG_IMMEDIATE(r8,__bss_start)
+ LOAD_REG_ADDR(r11,__bss_stop)
+ LOAD_REG_ADDR(r8,__bss_start)
sub r11,r11,r8 /* bss size */
addi r11,r11,7 /* round up to an even double word */
- rldicl. r11,r11,61,3 /* shift right by 3 */
+ srdi. r11,r11,3 /* shift right by 3 */
beq 4f
addi r8,r8,-8
li r0,0
@@ -1569,35 +1630,35 @@ _INIT_STATIC(start_here_multiplatform)
ori r6,r6,MSR_RI
mtmsrd r6 /* RI on */
- /* The following gets the stack and TOC set up with the regs */
+#ifdef CONFIG_RELOCATABLE
+ /* Save the physical address we're running at in kernstart_addr */
+ LOAD_REG_ADDR(r4, kernstart_addr)
+ clrldi r0,r25,2
+ std r0,0(r4)
+#endif
+
+ /* The following gets the stack set up with the regs */
/* pointing to the real addr of the kernel stack. This is */
/* all done to support the C function call below which sets */
/* up the htab. This is done because we have relocated the */
/* kernel but are still running in real mode. */
- LOAD_REG_IMMEDIATE(r3,init_thread_union)
- add r3,r3,r26
+ LOAD_REG_ADDR(r3,init_thread_union)
- /* set up a stack pointer (physical address) */
+ /* set up a stack pointer */
addi r1,r3,THREAD_SIZE
li r0,0
stdu r0,-STACK_FRAME_OVERHEAD(r1)
- /* set up the TOC (physical address) */
- LOAD_REG_IMMEDIATE(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
- add r2,r2,r26
-
/* Do very early kernel initializations, including initial hash table,
* stab and slb setup before we turn on relocation. */
/* Restore parameters passed from prom_init/kexec */
mr r3,r31
- bl .early_setup
+ bl .early_setup /* also sets r13 and SPRG3 */
- LOAD_REG_IMMEDIATE(r3, .start_here_common)
- LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
+ LOAD_REG_ADDR(r3, .start_here_common)
+ ld r4,PACAKMSR(r13)
mtspr SPRN_SRR0,r3
mtspr SPRN_SRR1,r4
rfid
@@ -1606,20 +1667,10 @@ _INIT_STATIC(start_here_multiplatform)
/* This is where all platforms converge execution */
_INIT_GLOBAL(start_here_common)
/* relocation is on at this point */
+ std r1,PACAKSAVE(r13)
- /* The following code sets up the SP and TOC now that we are */
- /* running with translation enabled. */
-
- LOAD_REG_IMMEDIATE(r3,init_thread_union)
-
- /* set up the stack */
- addi r1,r3,THREAD_SIZE
- li r0,0
- stdu r0,-STACK_FRAME_OVERHEAD(r1)
-
- /* Load the TOC */
+ /* Load the TOC (virtual address) */
ld r2,PACATOC(r13)
- std r1,PACAKSAVE(r13)
bl .setup_system
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 3cb52fa0eda..590304c24da 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -422,7 +422,6 @@ skpinv: addi r6,r6,1 /* Increment */
* r12 is pointer to the pte
*/
#ifdef CONFIG_PTE_64BIT
-#define PTE_FLAGS_OFFSET 4
#define FIND_PTE \
rlwinm r12, r10, 13, 19, 29; /* Compute pgdir/pmd offset */ \
lwzx r11, r12, r11; /* Get pgd/pmd entry */ \
@@ -431,7 +430,6 @@ skpinv: addi r6,r6,1 /* Increment */
rlwimi r12, r10, 23, 20, 28; /* Compute pte address */ \
lwz r11, 4(r12); /* Get pte entry */
#else
-#define PTE_FLAGS_OFFSET 0
#define FIND_PTE \
rlwimi r11, r10, 12, 20, 29; /* Create L1 (pgdir/pmd) address */ \
lwz r11, 0(r11); /* Get L1 entry */ \
@@ -579,13 +577,19 @@ interrupt_base:
FIND_PTE
andc. r13,r13,r11 /* Check permission */
- bne 2f /* Bail if permission mismach */
#ifdef CONFIG_PTE_64BIT
- lwz r13, 0(r12)
+#ifdef CONFIG_SMP
+ subf r10,r11,r12 /* create false data dep */
+ lwzx r13,r11,r10 /* Get upper pte bits */
+#else
+ lwz r13,0(r12) /* Get upper pte bits */
+#endif
#endif
- /* Jump to common tlb load */
+ bne 2f /* Bail if permission/valid mismach */
+
+ /* Jump to common tlb load */
b finish_tlb_load
2:
/* The bailout. Restore registers to pre-exception conditions
@@ -640,12 +644,18 @@ interrupt_base:
FIND_PTE
andc. r13,r13,r11 /* Check permission */
- bne 2f /* Bail if permission mismach */
#ifdef CONFIG_PTE_64BIT
- lwz r13, 0(r12)
+#ifdef CONFIG_SMP
+ subf r10,r11,r12 /* create false data dep */
+ lwzx r13,r11,r10 /* Get upper pte bits */
+#else
+ lwz r13,0(r12) /* Get upper pte bits */
+#endif
#endif
+ bne 2f /* Bail if permission mismach */
+
/* Jump to common TLB load point */
b finish_tlb_load
@@ -702,7 +712,7 @@ interrupt_base:
/*
* Both the instruction and data TLB miss get to this
* point to load the TLB.
- * r10 - EA of fault
+ * r10 - available to use
* r11 - TLB (info from Linux PTE)
* r12 - available to use
* r13 - upper bits of PTE (if PTE_64BIT) or available to use
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index 550a19399bf..ea1ba89f9c9 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -51,17 +51,6 @@ static int protect4gb = 1;
static void __iommu_free(struct iommu_table *, dma_addr_t, unsigned int);
-static inline unsigned long iommu_num_pages(unsigned long vaddr,
- unsigned long slen)
-{
- unsigned long npages;
-
- npages = IOMMU_PAGE_ALIGN(vaddr + slen) - (vaddr & IOMMU_PAGE_MASK);
- npages >>= IOMMU_PAGE_SHIFT;
-
- return npages;
-}
-
static int __init setup_protect4gb(char *str)
{
if (strcmp(str, "on") == 0)
@@ -325,7 +314,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
}
/* Allocate iommu entries for that segment */
vaddr = (unsigned long) sg_virt(s);
- npages = iommu_num_pages(vaddr, slen);
+ npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE);
align = 0;
if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
(vaddr & ~PAGE_MASK) == 0)
@@ -418,7 +407,8 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
unsigned long vaddr, npages;
vaddr = s->dma_address & IOMMU_PAGE_MASK;
- npages = iommu_num_pages(s->dma_address, s->dma_length);
+ npages = iommu_num_pages(s->dma_address, s->dma_length,
+ IOMMU_PAGE_SIZE);
__iommu_free(tbl, vaddr, npages);
s->dma_address = DMA_ERROR_CODE;
s->dma_length = 0;
@@ -452,7 +442,8 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
if (sg->dma_length == 0)
break;
- npages = iommu_num_pages(dma_handle, sg->dma_length);
+ npages = iommu_num_pages(dma_handle, sg->dma_length,
+ IOMMU_PAGE_SIZE);
__iommu_free(tbl, dma_handle, npages);
sg = sg_next(sg);
}
@@ -584,7 +575,7 @@ dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl,
BUG_ON(direction == DMA_NONE);
uaddr = (unsigned long)vaddr;
- npages = iommu_num_pages(uaddr, size);
+ npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE);
if (tbl) {
align = 0;
@@ -617,7 +608,7 @@ void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle,
BUG_ON(direction == DMA_NONE);
if (tbl) {
- npages = iommu_num_pages(dma_handle, size);
+ npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE);
iommu_free(tbl, dma_handle, npages);
}
}
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index d972decf032..ac222d0ab12 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -439,8 +439,8 @@ void do_softirq(void)
static LIST_HEAD(irq_hosts);
static DEFINE_SPINLOCK(irq_big_lock);
-static DEFINE_PER_CPU(unsigned int, irq_radix_reader);
-static unsigned int irq_radix_writer;
+static unsigned int revmap_trees_allocated;
+static DEFINE_MUTEX(revmap_trees_mutex);
struct irq_map_entry irq_map[NR_IRQS];
static unsigned int irq_virq_count = NR_IRQS;
static struct irq_host *irq_default_host;
@@ -583,57 +583,6 @@ void irq_set_virq_count(unsigned int count)
irq_virq_count = count;
}
-/* radix tree not lockless safe ! we use a brlock-type mecanism
- * for now, until we can use a lockless radix tree
- */
-static void irq_radix_wrlock(unsigned long *flags)
-{
- unsigned int cpu, ok;
-
- spin_lock_irqsave(&irq_big_lock, *flags);
- irq_radix_writer = 1;
- smp_mb();
- do {
- barrier();
- ok = 1;
- for_each_possible_cpu(cpu) {
- if (per_cpu(irq_radix_reader, cpu)) {
- ok = 0;
- break;
- }
- }
- if (!ok)
- cpu_relax();
- } while(!ok);
-}
-
-static void irq_radix_wrunlock(unsigned long flags)
-{
- smp_wmb();
- irq_radix_writer = 0;
- spin_unlock_irqrestore(&irq_big_lock, flags);
-}
-
-static void irq_radix_rdlock(unsigned long *flags)
-{
- local_irq_save(*flags);
- __get_cpu_var(irq_radix_reader) = 1;
- smp_mb();
- if (likely(irq_radix_writer == 0))
- return;
- __get_cpu_var(irq_radix_reader) = 0;
- smp_wmb();
- spin_lock(&irq_big_lock);
- __get_cpu_var(irq_radix_reader) = 1;
- spin_unlock(&irq_big_lock);
-}
-
-static void irq_radix_rdunlock(unsigned long flags)
-{
- __get_cpu_var(irq_radix_reader) = 0;
- local_irq_restore(flags);
-}
-
static int irq_setup_virq(struct irq_host *host, unsigned int virq,
irq_hw_number_t hwirq)
{
@@ -788,7 +737,6 @@ void irq_dispose_mapping(unsigned int virq)
{
struct irq_host *host;
irq_hw_number_t hwirq;
- unsigned long flags;
if (virq == NO_IRQ)
return;
@@ -821,12 +769,16 @@ void irq_dispose_mapping(unsigned int virq)
host->revmap_data.linear.revmap[hwirq] = NO_IRQ;
break;
case IRQ_HOST_MAP_TREE:
- /* Check if radix tree allocated yet */
- if (host->revmap_data.tree.gfp_mask == 0)
+ /*
+ * Check if radix tree allocated yet, if not then nothing to
+ * remove.
+ */
+ smp_rmb();
+ if (revmap_trees_allocated < 1)
break;
- irq_radix_wrlock(&flags);
+ mutex_lock(&revmap_trees_mutex);
radix_tree_delete(&host->revmap_data.tree, hwirq);
- irq_radix_wrunlock(flags);
+ mutex_unlock(&revmap_trees_mutex);
break;
}
@@ -875,43 +827,62 @@ unsigned int irq_find_mapping(struct irq_host *host,
EXPORT_SYMBOL_GPL(irq_find_mapping);
-unsigned int irq_radix_revmap(struct irq_host *host,
- irq_hw_number_t hwirq)
+unsigned int irq_radix_revmap_lookup(struct irq_host *host,
+ irq_hw_number_t hwirq)
{
- struct radix_tree_root *tree;
struct irq_map_entry *ptr;
unsigned int virq;
- unsigned long flags;
WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
- /* Check if the radix tree exist yet. We test the value of
- * the gfp_mask for that. Sneaky but saves another int in the
- * structure. If not, we fallback to slow mode
+ /*
+ * Check if the radix tree exists and has bee initialized.
+ * If not, we fallback to slow mode
*/
- tree = &host->revmap_data.tree;
- if (tree->gfp_mask == 0)
+ if (revmap_trees_allocated < 2)
return irq_find_mapping(host, hwirq);
/* Now try to resolve */
- irq_radix_rdlock(&flags);
- ptr = radix_tree_lookup(tree, hwirq);
- irq_radix_rdunlock(flags);
+ /*
+ * No rcu_read_lock(ing) needed, the ptr returned can't go under us
+ * as it's referencing an entry in the static irq_map table.
+ */
+ ptr = radix_tree_lookup(&host->revmap_data.tree, hwirq);
- /* Found it, return */
- if (ptr) {
+ /*
+ * If found in radix tree, then fine.
+ * Else fallback to linear lookup - this should not happen in practice
+ * as it means that we failed to insert the node in the radix tree.
+ */
+ if (ptr)
virq = ptr - irq_map;
- return virq;
- }
+ else
+ virq = irq_find_mapping(host, hwirq);
+
+ return virq;
+}
+
+void irq_radix_revmap_insert(struct irq_host *host, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+
+ WARN_ON(host->revmap_type != IRQ_HOST_MAP_TREE);
+
+ /*
+ * Check if the radix tree exists yet.
+ * If not, then the irq will be inserted into the tree when it gets
+ * initialized.
+ */
+ smp_rmb();
+ if (revmap_trees_allocated < 1)
+ return;
- /* If not there, try to insert it */
- virq = irq_find_mapping(host, hwirq);
if (virq != NO_IRQ) {
- irq_radix_wrlock(&flags);
- radix_tree_insert(tree, hwirq, &irq_map[virq]);
- irq_radix_wrunlock(flags);
+ mutex_lock(&revmap_trees_mutex);
+ radix_tree_insert(&host->revmap_data.tree, hwirq,
+ &irq_map[virq]);
+ mutex_unlock(&revmap_trees_mutex);
}
- return virq;
}
unsigned int irq_linear_revmap(struct irq_host *host,
@@ -1020,14 +991,44 @@ void irq_early_init(void)
static int irq_late_init(void)
{
struct irq_host *h;
- unsigned long flags;
+ unsigned int i;
- irq_radix_wrlock(&flags);
+ /*
+ * No mutual exclusion with respect to accessors of the tree is needed
+ * here as the synchronization is done via the state variable
+ * revmap_trees_allocated.
+ */
list_for_each_entry(h, &irq_hosts, link) {
if (h->revmap_type == IRQ_HOST_MAP_TREE)
- INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC);
+ INIT_RADIX_TREE(&h->revmap_data.tree, GFP_KERNEL);
+ }
+
+ /*
+ * Make sure the radix trees inits are visible before setting
+ * the flag
+ */
+ smp_wmb();
+ revmap_trees_allocated = 1;
+
+ /*
+ * Insert the reverse mapping for those interrupts already present
+ * in irq_map[].
+ */
+ mutex_lock(&revmap_trees_mutex);
+ for (i = 0; i < irq_virq_count; i++) {
+ if (irq_map[i].host &&
+ (irq_map[i].host->revmap_type == IRQ_HOST_MAP_TREE))
+ radix_tree_insert(&irq_map[i].host->revmap_data.tree,
+ irq_map[i].hwirq, &irq_map[i]);
}
- irq_radix_wrunlock(flags);
+ mutex_unlock(&revmap_trees_mutex);
+
+ /*
+ * Make sure the radix trees insertions are visible before setting
+ * the flag
+ */
+ smp_wmb();
+ revmap_trees_allocated = 2;
return 0;
}
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index b3eef30b513..d051e8cbcd0 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -510,10 +510,10 @@ static ssize_t update_ppp(u64 *entitlement, u8 *weight)
return -EINVAL;
pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
- __FUNCTION__, ppp_data.entitlement, ppp_data.weight);
+ __func__, ppp_data.entitlement, ppp_data.weight);
pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
- __FUNCTION__, new_entitled, new_weight);
+ __func__, new_entitled, new_weight);
retval = plpar_hcall_norets(H_SET_PPP, new_entitled, new_weight);
return retval;
@@ -556,10 +556,10 @@ static ssize_t update_mpp(u64 *entitlement, u8 *weight)
return -EINVAL;
pr_debug("%s: current_entitled = %lu, current_weight = %u\n",
- __FUNCTION__, mpp_data.entitled_mem, mpp_data.mem_weight);
+ __func__, mpp_data.entitled_mem, mpp_data.mem_weight);
pr_debug("%s: new_entitled = %lu, new_weight = %u\n",
- __FUNCTION__, new_entitled, new_weight);
+ __func__, new_entitled, new_weight);
rc = plpar_hcall_norets(H_SET_MPP, new_entitled, new_weight);
return rc;
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S
index 85cb6f34084..2d29752cbe1 100644
--- a/arch/powerpc/kernel/misc.S
+++ b/arch/powerpc/kernel/misc.S
@@ -31,11 +31,14 @@ _GLOBAL(reloc_offset)
mflr r0
bl 1f
1: mflr r3
- LOAD_REG_IMMEDIATE(r4,1b)
+ PPC_LL r4,(2f-1b)(r3)
subf r3,r4,r3
mtlr r0
blr
+ .align 3
+2: PPC_LONG 1b
+
/*
* add_reloc_offset(x) returns x + reloc_offset().
*/
@@ -43,12 +46,15 @@ _GLOBAL(add_reloc_offset)
mflr r0
bl 1f
1: mflr r5
- LOAD_REG_IMMEDIATE(r4,1b)
+ PPC_LL r4,(2f-1b)(r5)
subf r5,r4,r5
add r3,r3,r5
mtlr r0
blr
+ .align 3
+2: PPC_LONG 1b
+
_GLOBAL(kernel_execve)
li r0,__NR_execve
sc
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 7a6dfbca768..6a9b4bf0d17 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -274,6 +274,10 @@ _GLOBAL(real_writeb)
/*
* Flush MMU TLB
*/
+#ifndef CONFIG_FSL_BOOKE
+_GLOBAL(_tlbil_all)
+_GLOBAL(_tlbil_pid)
+#endif
_GLOBAL(_tlbia)
#if defined(CONFIG_40x)
sync /* Flush to memory before changing mapping */
@@ -344,6 +348,9 @@ _GLOBAL(_tlbia)
/*
* Flush MMU TLB for a particular address
*/
+#ifndef CONFIG_FSL_BOOKE
+_GLOBAL(_tlbil_va)
+#endif
_GLOBAL(_tlbie)
#if defined(CONFIG_40x)
/* We run the search with interrupts disabled because we have to change
@@ -436,6 +443,53 @@ _GLOBAL(_tlbie)
#endif /* ! CONFIG_40x */
blr
+#if defined(CONFIG_FSL_BOOKE)
+/*
+ * Flush MMU TLB, but only on the local processor (no broadcast)
+ */
+_GLOBAL(_tlbil_all)
+#define MMUCSR0_TLBFI (MMUCSR0_TLB0FI | MMUCSR0_TLB1FI | \
+ MMUCSR0_TLB2FI | MMUCSR0_TLB3FI)
+ li r3,(MMUCSR0_TLBFI)@l
+ mtspr SPRN_MMUCSR0, r3
+1:
+ mfspr r3,SPRN_MMUCSR0
+ andi. r3,r3,MMUCSR0_TLBFI@l
+ bne 1b
+ blr
+
+/*
+ * Flush MMU TLB for a particular process id, but only on the local processor
+ * (no broadcast)
+ */
+_GLOBAL(_tlbil_pid)
+/* we currently do an invalidate all since we don't have per pid invalidate */
+ li r3,(MMUCSR0_TLBFI)@l
+ mtspr SPRN_MMUCSR0, r3
+1:
+ mfspr r3,SPRN_MMUCSR0
+ andi. r3,r3,MMUCSR0_TLBFI@l
+ bne 1b
+ blr
+
+/*
+ * Flush MMU TLB for a particular address, but only on the local processor
+ * (no broadcast)
+ */
+_GLOBAL(_tlbil_va)
+ slwi r4,r4,16
+ mtspr SPRN_MAS6,r4 /* assume AS=0 for now */
+ tlbsx 0,r3
+ mfspr r4,SPRN_MAS1 /* check valid */
+ andis. r3,r4,MAS1_VALID@h
+ beqlr
+ rlwinm r4,r4,0,1,31
+ mtspr SPRN_MAS1,r4
+ tlbwe
+ blr
+#endif /* CONFIG_FSL_BOOKE */
+
+
/*
* Flush instruction cache.
* This is a no-op on the 601.
@@ -846,8 +900,10 @@ _GLOBAL(kernel_thread)
li r4,0 /* new sp (unused) */
li r0,__NR_clone
sc
- cmpwi 0,r3,0 /* parent or child? */
- bne 1f /* return if parent */
+ bns+ 1f /* did system call indicate error? */
+ neg r3,r3 /* if so, make return code negative */
+1: cmpwi 0,r3,0 /* parent or child? */
+ bne 2f /* return if parent */
li r0,0 /* make top-level stack frame */
stwu r0,-16(r1)
mtlr r30 /* fn addr in lr */
@@ -857,7 +913,7 @@ _GLOBAL(kernel_thread)
li r0,__NR_exit /* exit if function returns */
li r3,0
sc
-1: lwz r30,8(r1)
+2: lwz r30,8(r1)
lwz r31,12(r1)
addi r1,r1,16
blr
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index 4dd70cf7bb4..3053fe5c62f 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -426,8 +426,10 @@ _GLOBAL(kernel_thread)
li r4,0 /* new sp (unused) */
li r0,__NR_clone
sc
- cmpdi 0,r3,0 /* parent or child? */
- bne 1f /* return if parent */
+ bns+ 1f /* did system call indicate error? */
+ neg r3,r3 /* if so, make return code negative */
+1: cmpdi 0,r3,0 /* parent or child? */
+ bne 2f /* return if parent */
li r0,0
stdu r0,-STACK_FRAME_OVERHEAD(r1)
ld r2,8(r29)
@@ -438,7 +440,7 @@ _GLOBAL(kernel_thread)
li r0,__NR_exit /* exit after child exits */
li r3,0
sc
-1: addi r1,r1,STACK_FRAME_OVERHEAD
+2: addi r1,r1,STACK_FRAME_OVERHEAD
ld r29,-24(r1)
ld r30,-16(r1)
blr
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c
index e9be908f199..93ae5b169f4 100644
--- a/arch/powerpc/kernel/of_device.c
+++ b/arch/powerpc/kernel/of_device.c
@@ -78,7 +78,7 @@ struct of_device *of_device_alloc(struct device_node *np,
dev->dev.parent = parent;
dev->dev.release = of_release_dev;
dev->dev.archdata.of_node = np;
- dev->dev.archdata.numa_node = of_node_to_nid(np);
+ set_dev_node(&dev->dev, of_node_to_nid(np));
if (bus_id)
strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index c9bf17eec31..48a347133f4 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -12,6 +12,7 @@
#include <asm/lppaca.h>
#include <asm/paca.h>
+#include <asm/sections.h>
/* This symbol is provided by the linker - let it fill in the paca
* field correctly */
@@ -79,6 +80,8 @@ void __init initialise_pacas(void)
new_paca->lock_token = 0x8000;
new_paca->paca_index = cpu;
new_paca->kernel_toc = kernel_toc;
+ new_paca->kernelbase = (unsigned long) _stext;
+ new_paca->kernel_msr = MSR_KERNEL;
new_paca->hw_cpu_id = 0xffff;
new_paca->slb_shadow_ptr = &slb_shadow[cpu];
new_paca->__current = &init_task;
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index ea0c61e09b7..01ce8c38bae 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -56,6 +56,34 @@ resource_size_t isa_mem_base;
/* Default PCI flags is 0 */
unsigned int ppc_pci_flags;
+static struct dma_mapping_ops *pci_dma_ops;
+
+void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
+{
+ pci_dma_ops = dma_ops;
+}
+
+struct dma_mapping_ops *get_pci_dma_ops(void)
+{
+ return pci_dma_ops;
+}
+EXPORT_SYMBOL(get_pci_dma_ops);
+
+int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
+{
+ return dma_set_mask(&dev->dev, mask);
+}
+
+int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
+{
+ int rc;
+
+ rc = dma_set_mask(&dev->dev, mask);
+ dev->dev.coherent_dma_mask = dev->dma_mask;
+
+ return rc;
+}
+
struct pci_controller *pcibios_alloc_controller(struct device_node *dev)
{
struct pci_controller *phb;
@@ -180,6 +208,26 @@ char __devinit *pcibios_setup(char *str)
return str;
}
+void __devinit pcibios_setup_new_device(struct pci_dev *dev)
+{
+ struct dev_archdata *sd = &dev->dev.archdata;
+
+ sd->of_node = pci_device_to_OF_node(dev);
+
+ DBG("PCI: device %s OF node: %s\n", pci_name(dev),
+ sd->of_node ? sd->of_node->full_name : "<none>");
+
+ sd->dma_ops = pci_dma_ops;
+#ifdef CONFIG_PPC32
+ sd->dma_data = (void *)PCI_DRAM_OFFSET;
+#endif
+ set_dev_node(&dev->dev, pcibus_to_node(dev->bus));
+
+ if (ppc_md.pci_dma_dev_setup)
+ ppc_md.pci_dma_dev_setup(dev);
+}
+EXPORT_SYMBOL(pcibios_setup_new_device);
+
/*
* Reads the interrupt pin to determine if interrupt is use by card.
* If the interrupt is used, then gets the interrupt line from the
@@ -371,7 +419,7 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
struct pci_dev *pdev = NULL;
struct resource *found = NULL;
unsigned long prot = pgprot_val(protection);
- unsigned long offset = pfn << PAGE_SHIFT;
+ resource_size_t offset = ((resource_size_t)pfn) << PAGE_SHIFT;
int i;
if (page_is_ram(pfn))
@@ -422,7 +470,8 @@ pgprot_t pci_phys_mem_access_prot(struct file *file,
int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine)
{
- resource_size_t offset = vma->vm_pgoff << PAGE_SHIFT;
+ resource_size_t offset =
+ ((resource_size_t)vma->vm_pgoff) << PAGE_SHIFT;
struct resource *rp;
int ret;
@@ -731,11 +780,6 @@ static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev)
res->start = (res->start + offset) & mask;
res->end = (res->end + offset) & mask;
-
- pr_debug("PCI:%s %016llx-%016llx\n",
- pci_name(dev),
- (unsigned long long)res->start,
- (unsigned long long)res->end);
}
@@ -781,6 +825,11 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
(unsigned int)res->flags);
fixup_resource(res, dev);
+
+ pr_debug("PCI:%s %016llx-%016llx\n",
+ pci_name(dev),
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
}
/* Call machine specific resource fixup */
@@ -789,58 +838,127 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources);
-static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+/* This function tries to figure out if a bridge resource has been initialized
+ * by the firmware or not. It doesn't have to be absolutely bullet proof, but
+ * things go more smoothly when it gets it right. It should covers cases such
+ * as Apple "closed" bridge resources and bare-metal pSeries unassigned bridges
+ */
+static int __devinit pcibios_uninitialized_bridge_resource(struct pci_bus *bus,
+ struct resource *res)
{
struct pci_controller *hose = pci_bus_to_host(bus);
struct pci_dev *dev = bus->self;
+ resource_size_t offset;
+ u16 command;
+ int i;
- pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
+ /* We don't do anything if PCI_PROBE_ONLY is set */
+ if (ppc_pci_flags & PPC_PCI_PROBE_ONLY)
+ return 0;
- /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
- * now differently between 32 and 64 bits.
- */
- if (dev != NULL) {
- struct resource *res;
- int i;
+ /* Job is a bit different between memory and IO */
+ if (res->flags & IORESOURCE_MEM) {
+ /* If the BAR is non-0 (res != pci_mem_offset) then it's probably been
+ * initialized by somebody
+ */
+ if (res->start != hose->pci_mem_offset)
+ return 0;
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
- if ((res = bus->resource[i]) == NULL)
- continue;
- if (!res->flags)
- continue;
- if (i >= 3 && bus->self->transparent)
- continue;
- /* On PowerMac, Apple leaves bridge windows open over
- * an inaccessible region of memory space (0...fffff)
- * which is somewhat bogus, but that's what they think
- * means disabled...
- *
- * We clear those to force them to be reallocated later
- *
- * We detect such regions by the fact that the base is
- * equal to the pci_mem_offset of the host bridge and
- * their size is smaller than 1M.
- */
- if (res->flags & IORESOURCE_MEM &&
- res->start == hose->pci_mem_offset &&
- res->end < 0x100000) {
- printk(KERN_INFO
- "PCI: Closing bogus Apple Firmware"
- " region %d on bus 0x%02x\n",
- i, bus->number);
- res->flags = 0;
- continue;
- }
+ /* The BAR is 0, let's check if memory decoding is enabled on
+ * the bridge. If not, we consider it unassigned
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if ((command & PCI_COMMAND_MEMORY) == 0)
+ return 1;
- pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
- pci_name(dev), i,
- (unsigned long long)res->start,\
- (unsigned long long)res->end,
- (unsigned int)res->flags);
+ /* Memory decoding is enabled and the BAR is 0. If any of the bridge
+ * resources covers that starting address (0 then it's good enough for
+ * us for memory
+ */
+ for (i = 0; i < 3; i++) {
+ if ((hose->mem_resources[i].flags & IORESOURCE_MEM) &&
+ hose->mem_resources[i].start == hose->pci_mem_offset)
+ return 0;
+ }
- fixup_resource(res, dev);
+ /* Well, it starts at 0 and we know it will collide so we may as
+ * well consider it as unassigned. That covers the Apple case.
+ */
+ return 1;
+ } else {
+ /* If the BAR is non-0, then we consider it assigned */
+ offset = (unsigned long)hose->io_base_virt - _IO_BASE;
+ if (((res->start - offset) & 0xfffffffful) != 0)
+ return 0;
+
+ /* Here, we are a bit different than memory as typically IO space
+ * starting at low addresses -is- valid. What we do instead if that
+ * we consider as unassigned anything that doesn't have IO enabled
+ * in the PCI command register, and that's it.
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & PCI_COMMAND_IO)
+ return 0;
+
+ /* It's starting at 0 and IO is disabled in the bridge, consider
+ * it unassigned
+ */
+ return 1;
+ }
+}
+
+/* Fixup resources of a PCI<->PCI bridge */
+static void __devinit pcibios_fixup_bridge(struct pci_bus *bus)
+{
+ struct resource *res;
+ int i;
+
+ struct pci_dev *dev = bus->self;
+
+ for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) {
+ if ((res = bus->resource[i]) == NULL)
+ continue;
+ if (!res->flags)
+ continue;
+ if (i >= 3 && bus->self->transparent)
+ continue;
+
+ pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n",
+ pci_name(dev), i,
+ (unsigned long long)res->start,\
+ (unsigned long long)res->end,
+ (unsigned int)res->flags);
+
+ /* Perform fixup */
+ fixup_resource(res, dev);
+
+ /* Try to detect uninitialized P2P bridge resources,
+ * and clear them out so they get re-assigned later
+ */
+ if (pcibios_uninitialized_bridge_resource(bus, res)) {
+ res->flags = 0;
+ pr_debug("PCI:%s (unassigned)\n", pci_name(dev));
+ } else {
+
+ pr_debug("PCI:%s %016llx-%016llx\n",
+ pci_name(dev),
+ (unsigned long long)res->start,
+ (unsigned long long)res->end);
}
}
+}
+
+static void __devinit __pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct pci_dev *dev = bus->self;
+
+ pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB");
+
+ /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for
+ * now differently between 32 and 64 bits.
+ */
+ if (dev != NULL)
+ pcibios_fixup_bridge(bus);
/* Additional setup that is different between 32 and 64 bits for now */
pcibios_do_bus_setup(bus);
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 88db4ffaf11..131b1dfa68c 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -53,12 +53,19 @@ LIST_HEAD(hose_list);
static int pci_bus_count;
+/* This will remain NULL for now, until isa-bridge.c is made common
+ * to both 32-bit and 64-bit.
+ */
+struct pci_dev *isa_bridge_pcidev;
+EXPORT_SYMBOL_GPL(isa_bridge_pcidev);
+
static void
-fixup_hide_host_resource_fsl(struct pci_dev* dev)
+fixup_hide_host_resource_fsl(struct pci_dev *dev)
{
int i, class = dev->class >> 8;
- if ((class == PCI_CLASS_PROCESSOR_POWERPC) &&
+ if ((class == PCI_CLASS_PROCESSOR_POWERPC ||
+ class == PCI_CLASS_BRIDGE_OTHER) &&
(dev->hdr_type == PCI_HEADER_TYPE_NORMAL) &&
(dev->bus->parent == NULL)) {
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
@@ -424,6 +431,7 @@ void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
unsigned long io_offset;
struct resource *res;
int i;
+ struct pci_dev *dev;
/* Hookup PHB resources */
io_offset = (unsigned long)hose->io_base_virt - isa_io_base;
@@ -457,6 +465,12 @@ void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
bus->resource[i+1] = res;
}
}
+
+ if (ppc_md.pci_dma_bus_setup)
+ ppc_md.pci_dma_bus_setup(bus);
+
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ pcibios_setup_new_device(dev);
}
/* the next one is stolen from the alpha port... */
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index 30eedfc5a56..8247cff1cb3 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -52,35 +52,6 @@ EXPORT_SYMBOL(pci_io_base);
LIST_HEAD(hose_list);
-static struct dma_mapping_ops *pci_dma_ops;
-
-void set_pci_dma_ops(struct dma_mapping_ops *dma_ops)
-{
- pci_dma_ops = dma_ops;
-}
-
-struct dma_mapping_ops *get_pci_dma_ops(void)
-{
- return pci_dma_ops;
-}
-EXPORT_SYMBOL(get_pci_dma_ops);
-
-
-int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
-{
- return dma_set_mask(&dev->dev, mask);
-}
-
-int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
-{
- int rc;
-
- rc = dma_set_mask(&dev->dev, mask);
- dev->dev.coherent_dma_mask = dev->dma_mask;
-
- return rc;
-}
-
static void fixup_broken_pcnet32(struct pci_dev* dev)
{
if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) {
@@ -548,26 +519,6 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus)
}
EXPORT_SYMBOL_GPL(pcibios_map_io_space);
-void __devinit pcibios_setup_new_device(struct pci_dev *dev)
-{
- struct dev_archdata *sd = &dev->dev.archdata;
-
- sd->of_node = pci_device_to_OF_node(dev);
-
- DBG("PCI: device %s OF node: %s\n", pci_name(dev),
- sd->of_node ? sd->of_node->full_name : "<none>");
-
- sd->dma_ops = pci_dma_ops;
-#ifdef CONFIG_NUMA
- sd->numa_node = pcibus_to_node(dev->bus);
-#else
- sd->numa_node = -1;
-#endif
- if (ppc_md.pci_dma_dev_setup)
- ppc_md.pci_dma_dev_setup(dev);
-}
-EXPORT_SYMBOL(pcibios_setup_new_device);
-
void __devinit pcibios_do_bus_setup(struct pci_bus *bus)
{
struct pci_dev *dev;
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index e1ea4fe5cfb..8edc2359c41 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -119,6 +119,9 @@ EXPORT_SYMBOL(flush_instruction_cache);
EXPORT_SYMBOL(flush_tlb_kernel_range);
EXPORT_SYMBOL(flush_tlb_page);
EXPORT_SYMBOL(_tlbie);
+#if defined(CONFIG_4xx) || defined(CONFIG_8xx) || defined(CONFIG_FSL_BOOKE)
+EXPORT_SYMBOL(_tlbil_va);
+#endif
#endif
EXPORT_SYMBOL(__flush_icache_range);
EXPORT_SYMBOL(flush_dcache_range);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 87d83c56b31..3a2dc7e6586 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -888,9 +888,10 @@ static u64 __init dt_mem_next_cell(int s, cell_t **cellp)
*/
static int __init early_init_dt_scan_drconf_memory(unsigned long node)
{
- cell_t *dm, *ls;
+ cell_t *dm, *ls, *usm;
unsigned long l, n, flags;
u64 base, size, lmb_size;
+ unsigned int is_kexec_kdump = 0, rngs;
ls = (cell_t *)of_get_flat_dt_prop(node, "ibm,lmb-size", &l);
if (ls == NULL || l < dt_root_size_cells * sizeof(cell_t))
@@ -905,6 +906,12 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
if (l < (n * (dt_root_addr_cells + 4) + 1) * sizeof(cell_t))
return 0;
+ /* check if this is a kexec/kdump kernel. */
+ usm = (cell_t *)of_get_flat_dt_prop(node, "linux,drconf-usable-memory",
+ &l);
+ if (usm != NULL)
+ is_kexec_kdump = 1;
+
for (; n != 0; --n) {
base = dt_mem_next_cell(dt_root_addr_cells, &dm);
flags = dm[3];
@@ -915,13 +922,34 @@ static int __init early_init_dt_scan_drconf_memory(unsigned long node)
if ((flags & 0x80) || !(flags & 0x8))
continue;
size = lmb_size;
- if (iommu_is_off) {
- if (base >= 0x80000000ul)
+ rngs = 1;
+ if (is_kexec_kdump) {
+ /*
+ * For each lmb in ibm,dynamic-memory, a corresponding
+ * entry in linux,drconf-usable-memory property contains
+ * a counter 'p' followed by 'p' (base, size) duple.
+ * Now read the counter from
+ * linux,drconf-usable-memory property
+ */
+ rngs = dt_mem_next_cell(dt_root_size_cells, &usm);
+ if (!rngs) /* there are no (base, size) duple */
continue;
- if ((base + size) > 0x80000000ul)
- size = 0x80000000ul - base;
}
- lmb_add(base, size);
+ do {
+ if (is_kexec_kdump) {
+ base = dt_mem_next_cell(dt_root_addr_cells,
+ &usm);
+ size = dt_mem_next_cell(dt_root_size_cells,
+ &usm);
+ }
+ if (iommu_is_off) {
+ if (base >= 0x80000000ul)
+ continue;
+ if ((base + size) > 0x80000000ul)
+ size = 0x80000000ul - base;
+ }
+ lmb_add(base, size);
+ } while (--rngs);
}
lmb_dump_all();
return 0;
@@ -1164,6 +1192,9 @@ void __init early_init_devtree(void *params)
/* Reserve LMB regions used by kernel, initrd, dt, etc... */
lmb_reserve(PHYSICAL_START, __pa(klimit) - PHYSICAL_START);
+ /* If relocatable, reserve first 32k for interrupt vectors etc. */
+ if (PHYSICAL_START > MEMORY_START)
+ lmb_reserve(MEMORY_START, 0x8000);
reserve_kdump_trampoline();
reserve_crashkernel();
early_reserve_mem();
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index b72849ac7db..2fdbc18ae94 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -732,7 +732,7 @@ static struct fake_elf {
u32 ignore_me;
} rpadesc;
} rpanote;
-} fake_elf = {
+} fake_elf __section(.fakeelf) = {
.elfhdr = {
.e_ident = { 0x7f, 'E', 'L', 'F',
ELFCLASS32, ELFDATA2MSB, EV_CURRENT },
@@ -774,13 +774,13 @@ static struct fake_elf {
.type = 0x12759999,
.name = "IBM,RPA-Client-Config",
.rpadesc = {
- .lpar_affinity = 0,
- .min_rmo_size = 64, /* in megabytes */
+ .lpar_affinity = 1,
+ .min_rmo_size = 128, /* in megabytes */
.min_rmo_percent = 0,
- .max_pft_size = 48, /* 2^48 bytes max PFT size */
+ .max_pft_size = 46, /* 2^46 bytes max PFT size */
.splpar = 1,
.min_load = ~0U,
- .new_mem_def = 0
+ .new_mem_def = 1
}
}
};
@@ -1321,7 +1321,7 @@ static void __init prom_initialize_tce_table(void)
*
* -- Cort
*/
-extern void __secondary_hold(void);
+extern char __secondary_hold;
extern unsigned long __secondary_hold_spinloop;
extern unsigned long __secondary_hold_acknowledge;
@@ -1342,13 +1342,7 @@ static void __init prom_hold_cpus(void)
= (void *) LOW_ADDR(__secondary_hold_spinloop);
unsigned long *acknowledge
= (void *) LOW_ADDR(__secondary_hold_acknowledge);
-#ifdef CONFIG_PPC64
- /* __secondary_hold is actually a descriptor, not the text address */
- unsigned long secondary_hold
- = __pa(*PTRRELOC((unsigned long *)__secondary_hold));
-#else
unsigned long secondary_hold = LOW_ADDR(__secondary_hold);
-#endif
prom_debug("prom_hold_cpus: start...\n");
prom_debug(" 1) spinloop = 0x%x\n", (unsigned long)spinloop);
@@ -2315,13 +2309,14 @@ static void __init prom_check_initrd(unsigned long r3, unsigned long r4)
unsigned long __init prom_init(unsigned long r3, unsigned long r4,
unsigned long pp,
- unsigned long r6, unsigned long r7)
+ unsigned long r6, unsigned long r7,
+ unsigned long kbase)
{
struct prom_t *_prom;
unsigned long hdr;
- unsigned long offset = reloc_offset();
#ifdef CONFIG_PPC32
+ unsigned long offset = reloc_offset();
reloc_got2(offset);
#endif
@@ -2355,9 +2350,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
*/
RELOC(of_platform) = prom_find_machine_type();
+#ifndef CONFIG_RELOCATABLE
/* Bail if this is a kdump kernel. */
if (PHYSICAL_START > 0)
prom_panic("Error: You can't boot a kdump kernel from OF!\n");
+#endif
/*
* Check for an initrd
@@ -2377,7 +2374,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
* Copy the CPU hold code
*/
if (RELOC(of_platform) != PLATFORM_POWERMAC)
- copy_and_flush(0, KERNELBASE + offset, 0x100, 0);
+ copy_and_flush(0, kbase, 0x100, 0);
/*
* Do early parsing of command line
@@ -2480,7 +2477,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
reloc_got2(-offset);
#endif
- __start(hdr, KERNELBASE + offset, 0);
+ __start(hdr, kbase, 0);
return 0;
}
diff --git a/arch/powerpc/kernel/reloc_64.S b/arch/powerpc/kernel/reloc_64.S
new file mode 100644
index 00000000000..b47a0e1ab00
--- /dev/null
+++ b/arch/powerpc/kernel/reloc_64.S
@@ -0,0 +1,87 @@
+/*
+ * Code to process dynamic relocations in the kernel.
+ *
+ * Copyright 2008 Paul Mackerras, 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 <asm/ppc_asm.h>
+
+RELA = 7
+RELACOUNT = 0x6ffffff9
+R_PPC64_RELATIVE = 22
+
+/*
+ * r3 = desired final address of kernel
+ */
+_GLOBAL(relocate)
+ mflr r0
+ bcl 20,31,$+4
+0: mflr r12 /* r12 has runtime addr of label 0 */
+ mtlr r0
+ ld r11,(p_dyn - 0b)(r12)
+ add r11,r11,r12 /* r11 has runtime addr of .dynamic section */
+ ld r9,(p_rela - 0b)(r12)
+ add r9,r9,r12 /* r9 has runtime addr of .rela.dyn section */
+ ld r10,(p_st - 0b)(r12)
+ add r10,r10,r12 /* r10 has runtime addr of _stext */
+
+ /*
+ * Scan the dynamic section for the RELA and RELACOUNT entries.
+ */
+ li r7,0
+ li r8,0
+1: ld r6,0(r11) /* get tag */
+ cmpdi r6,0
+ beq 4f /* end of list */
+ cmpdi r6,RELA
+ bne 2f
+ ld r7,8(r11) /* get RELA pointer in r7 */
+ b 3f
+2: addis r6,r6,(-RELACOUNT)@ha
+ cmpdi r6,RELACOUNT@l
+ bne 3f
+ ld r8,8(r11) /* get RELACOUNT value in r8 */
+3: addi r11,r11,16
+ b 1b
+4: cmpdi r7,0 /* check we have both RELA and RELACOUNT */
+ cmpdi cr1,r8,0
+ beq 6f
+ beq cr1,6f
+
+ /*
+ * Work out linktime address of _stext and hence the
+ * relocation offset to be applied.
+ * cur_offset [r7] = rela.run [r9] - rela.link [r7]
+ * _stext.link [r10] = _stext.run [r10] - cur_offset [r7]
+ * final_offset [r3] = _stext.final [r3] - _stext.link [r10]
+ */
+ subf r7,r7,r9 /* cur_offset */
+ subf r10,r7,r10
+ subf r3,r10,r3 /* final_offset */
+
+ /*
+ * Run through the list of relocations and process the
+ * R_PPC64_RELATIVE ones.
+ */
+ mtctr r8
+5: lwz r0,12(9) /* ELF64_R_TYPE(reloc->r_info) */
+ cmpwi r0,R_PPC64_RELATIVE
+ bne 6f
+ ld r6,0(r9) /* reloc->r_offset */
+ ld r0,16(r9) /* reloc->r_addend */
+ add r0,r0,r3
+ stdx r0,r7,r6
+ addi r9,r9,24
+ bdnz 5b
+
+6: blr
+
+p_dyn: .llong __dynamic_start - 0b
+p_rela: .llong __rela_dyn_start - 0b
+p_st: .llong _stext - 0b
+
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 9cc5a52711e..5ec56ff03e8 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -254,8 +254,21 @@ static int show_cpuinfo(struct seq_file *m, void *v)
/* If we are a Freescale core do a simple check so
* we dont have to keep adding cases in the future */
if (PVR_VER(pvr) & 0x8000) {
- maj = PVR_MAJ(pvr);
- min = PVR_MIN(pvr);
+ switch (PVR_VER(pvr)) {
+ case 0x8000: /* 7441/7450/7451, Voyager */
+ case 0x8001: /* 7445/7455, Apollo 6 */
+ case 0x8002: /* 7447/7457, Apollo 7 */
+ case 0x8003: /* 7447A, Apollo 7 PM */
+ case 0x8004: /* 7448, Apollo 8 */
+ case 0x800c: /* 7410, Nitro */
+ maj = ((pvr >> 8) & 0xF);
+ min = PVR_MIN(pvr);
+ break;
+ default: /* e500/book-e */
+ maj = PVR_MAJ(pvr);
+ min = PVR_MIN(pvr);
+ break;
+ }
} else {
switch (PVR_VER(pvr)) {
case 0x0020: /* 403 family */
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 066e65c59b5..c1a27626a94 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -111,7 +111,7 @@ notrace unsigned long __init early_init(unsigned long dt_ptr)
* This is called very early on the boot process, after a minimal
* MMU environment has been set up but before MMU_init is called.
*/
-notrace void __init machine_init(unsigned long dt_ptr, unsigned long phys)
+notrace void __init machine_init(unsigned long dt_ptr)
{
/* Enable early debugging if any specified (see udbg.h) */
udbg_early_init();
@@ -209,23 +209,12 @@ EXPORT_SYMBOL(nvram_sync);
#endif /* CONFIG_NVRAM */
-static DEFINE_PER_CPU(struct cpu, cpu_devices);
-
int __init ppc_init(void)
{
- int cpu;
-
/* clear the progress line */
if (ppc_md.progress)
ppc_md.progress(" ", 0xffff);
- /* register CPU devices */
- for_each_possible_cpu(cpu) {
- struct cpu *c = &per_cpu(cpu_devices, cpu);
- c->hotpluggable = 1;
- register_cpu(c, cpu);
- }
-
/* call platform init */
if (ppc_md.init != NULL) {
ppc_md.init();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 8b25f51f03b..843c0af210d 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -255,9 +255,11 @@ void early_setup_secondary(void)
#endif /* CONFIG_SMP */
#if defined(CONFIG_SMP) || defined(CONFIG_KEXEC)
+extern unsigned long __secondary_hold_spinloop;
+extern void generic_secondary_smp_init(void);
+
void smp_release_cpus(void)
{
- extern unsigned long __secondary_hold_spinloop;
unsigned long *ptr;
DBG(" -> smp_release_cpus()\n");
@@ -266,12 +268,11 @@ void smp_release_cpus(void)
* all now so they can start to spin on their individual paca
* spinloops. For non SMP kernels, the secondary cpus never get out
* of the common spinloop.
- * This is useless but harmless on iSeries, secondaries are already
- * waiting on their paca spinloops. */
+ */
ptr = (unsigned long *)((unsigned long)&__secondary_hold_spinloop
- PHYSICAL_START);
- *ptr = 1;
+ *ptr = __pa(generic_secondary_smp_init);
mb();
DBG(" <- smp_release_cpus()\n");
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index c27b10a1bd7..ff9f7010097 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -101,8 +101,7 @@ void smp_message_recv(int msg)
generic_smp_call_function_interrupt();
break;
case PPC_MSG_RESCHEDULE:
- /* XXX Do we have to do this? */
- set_need_resched();
+ /* we notice need_resched on exit */
break;
case PPC_MSG_CALL_FUNC_SINGLE:
generic_smp_call_function_single_interrupt();
diff --git a/arch/powerpc/kernel/swsusp_asm64.S b/arch/powerpc/kernel/swsusp_asm64.S
index e092c3cbdb9..86ac1d90d02 100644
--- a/arch/powerpc/kernel/swsusp_asm64.S
+++ b/arch/powerpc/kernel/swsusp_asm64.S
@@ -133,7 +133,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
cmpdi r12,0
beq- nothing_to_copy
- li r15,512
+ li r15,PAGE_SIZE>>3
copyloop:
ld r13,pbe_address(r12)
ld r14,pbe_orig_address(r12)
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index d98634c7606..bb1cfcfdbbb 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -61,42 +61,6 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x));
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
- compat_ino_t ino;
- long err;
-
- if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
- !new_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- ino = stat->ino;
- if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
- return -EOVERFLOW;
-
- err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
- err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
- err |= __put_user(ino, &statbuf->st_ino);
- err |= __put_user(stat->mode, &statbuf->st_mode);
- err |= __put_user(stat->nlink, &statbuf->st_nlink);
- err |= __put_user(stat->uid, &statbuf->st_uid);
- err |= __put_user(stat->gid, &statbuf->st_gid);
- err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev);
- err |= __put_user(stat->size, &statbuf->st_size);
- err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime);
- err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
- err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
- err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
- err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
- err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
- err |= __put_user(stat->blksize, &statbuf->st_blksize);
- err |= __put_user(stat->blocks, &statbuf->st_blocks);
- err |= __put_user(0, &statbuf->__unused4[0]);
- err |= __put_user(0, &statbuf->__unused4[1]);
-
- return err;
-}
-
/* Note: it is necessary to treat option as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -107,77 +71,6 @@ asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2)
return sys_sysfs((int)option, arg1, arg2);
}
-asmlinkage long compat_sys_pause(void)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule();
-
- return -ERESTARTNOHAND;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
- long usec;
-
- if (!access_ok(VERIFY_READ, i, sizeof(*i)))
- return -EFAULT;
- if (__get_user(o->tv_sec, &i->tv_sec))
- return -EFAULT;
- if (__get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
- return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
- (__put_user(i->tv_sec, &o->tv_sec) |
- __put_user(i->tv_usec, &o->tv_usec)));
-}
-
-
-
-
-/* Translations due to time_t size differences. Which affects all
- sorts of things, like timeval and itimerval. */
-extern struct timezone sys_tz;
-
-asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
-
- return 0;
-}
-
-
-
-asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_ts32(&kts, tv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
#ifdef CONFIG_SYSVIPC
long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr,
u32 fifth)
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 56d172d16e5..86a2ffccef2 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -15,18 +15,24 @@
#include <asm/firmware.h>
#include <asm/hvcall.h>
#include <asm/prom.h>
-#include <asm/paca.h>
-#include <asm/lppaca.h>
#include <asm/machdep.h>
#include <asm/smp.h>
+#ifdef CONFIG_PPC64
+#include <asm/paca.h>
+#include <asm/lppaca.h>
+#endif
+
static DEFINE_PER_CPU(struct cpu, cpu_devices);
static DEFINE_PER_CPU(struct kobject *, cache_toplevel);
-/* SMT stuff */
+/*
+ * SMT snooze delay stuff, 64-bit only for now
+ */
+
+#ifdef CONFIG_PPC64
-#ifdef CONFIG_PPC_MULTIPLATFORM
/* Time in microseconds we delay before sleeping in the idle loop */
DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 };
@@ -106,7 +112,7 @@ static int __init setup_smt_snooze_delay(char *str)
}
__setup("smt-snooze-delay=", setup_smt_snooze_delay);
-#endif /* CONFIG_PPC_MULTIPLATFORM */
+#endif /* CONFIG_PPC64 */
/*
* Enabling PMCs will slow partition context switch times so we only do
@@ -115,7 +121,7 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay);
static DEFINE_PER_CPU(char, pmcs_enabled);
-void ppc64_enable_pmcs(void)
+void ppc_enable_pmcs(void)
{
/* Only need to enable them once */
if (__get_cpu_var(pmcs_enabled))
@@ -126,8 +132,9 @@ void ppc64_enable_pmcs(void)
if (ppc_md.enable_pmcs)
ppc_md.enable_pmcs();
}
-EXPORT_SYMBOL(ppc64_enable_pmcs);
+EXPORT_SYMBOL(ppc_enable_pmcs);
+#if defined(CONFIG_6xx) || defined(CONFIG_PPC64)
/* XXX convert to rusty's on_one_cpu */
static unsigned long run_on_cpu(unsigned long cpu,
unsigned long (*func)(unsigned long),
@@ -146,6 +153,7 @@ static unsigned long run_on_cpu(unsigned long cpu,
return ret;
}
+#endif
#define SYSFS_PMCSETUP(NAME, ADDRESS) \
static unsigned long read_##NAME(unsigned long junk) \
@@ -154,7 +162,7 @@ static unsigned long read_##NAME(unsigned long junk) \
} \
static unsigned long write_##NAME(unsigned long val) \
{ \
- ppc64_enable_pmcs(); \
+ ppc_enable_pmcs(); \
mtspr(ADDRESS, val); \
return 0; \
} \
@@ -184,28 +192,53 @@ static ssize_t __used \
* that are implemented on the current processor
*/
+#if defined(CONFIG_PPC64)
+#define HAS_PPC_PMC_CLASSIC 1
+#define HAS_PPC_PMC_IBM 1
+#define HAS_PPC_PMC_PA6T 1
+#elif defined(CONFIG_6xx)
+#define HAS_PPC_PMC_CLASSIC 1
+#define HAS_PPC_PMC_IBM 1
+#define HAS_PPC_PMC_G4 1
+#endif
+
+
+#ifdef HAS_PPC_PMC_CLASSIC
SYSFS_PMCSETUP(mmcr0, SPRN_MMCR0);
SYSFS_PMCSETUP(mmcr1, SPRN_MMCR1);
-SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
SYSFS_PMCSETUP(pmc1, SPRN_PMC1);
SYSFS_PMCSETUP(pmc2, SPRN_PMC2);
SYSFS_PMCSETUP(pmc3, SPRN_PMC3);
SYSFS_PMCSETUP(pmc4, SPRN_PMC4);
SYSFS_PMCSETUP(pmc5, SPRN_PMC5);
SYSFS_PMCSETUP(pmc6, SPRN_PMC6);
+
+#ifdef HAS_PPC_PMC_G4
+SYSFS_PMCSETUP(mmcr2, SPRN_MMCR2);
+#endif
+
+#ifdef CONFIG_PPC64
SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
+
+SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
SYSFS_PMCSETUP(purr, SPRN_PURR);
SYSFS_PMCSETUP(spurr, SPRN_SPURR);
SYSFS_PMCSETUP(dscr, SPRN_DSCR);
+static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
+static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
+static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
+static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
+#endif /* CONFIG_PPC64 */
+
+#ifdef HAS_PPC_PMC_PA6T
SYSFS_PMCSETUP(pa6t_pmc0, SPRN_PA6T_PMC0);
SYSFS_PMCSETUP(pa6t_pmc1, SPRN_PA6T_PMC1);
SYSFS_PMCSETUP(pa6t_pmc2, SPRN_PA6T_PMC2);
SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
-
#ifdef CONFIG_DEBUG_KERNEL
SYSFS_PMCSETUP(hid0, SPRN_HID0);
SYSFS_PMCSETUP(hid1, SPRN_HID1);
@@ -236,28 +269,37 @@ SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1);
SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2);
SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3);
#endif /* CONFIG_DEBUG_KERNEL */
+#endif /* HAS_PPC_PMC_PA6T */
-static SYSDEV_ATTR(mmcra, 0600, show_mmcra, store_mmcra);
-static SYSDEV_ATTR(spurr, 0600, show_spurr, NULL);
-static SYSDEV_ATTR(dscr, 0600, show_dscr, store_dscr);
-static SYSDEV_ATTR(purr, 0600, show_purr, store_purr);
-
+#ifdef HAS_PPC_PMC_IBM
static struct sysdev_attribute ibm_common_attrs[] = {
_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
};
+#endif /* HAS_PPC_PMC_G4 */
+
+#ifdef HAS_PPC_PMC_G4
+static struct sysdev_attribute g4_common_attrs[] = {
+ _SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
+ _SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
+ _SYSDEV_ATTR(mmcr2, 0600, show_mmcr2, store_mmcr2),
+};
+#endif /* HAS_PPC_PMC_G4 */
-static struct sysdev_attribute ibm_pmc_attrs[] = {
+static struct sysdev_attribute classic_pmc_attrs[] = {
_SYSDEV_ATTR(pmc1, 0600, show_pmc1, store_pmc1),
_SYSDEV_ATTR(pmc2, 0600, show_pmc2, store_pmc2),
_SYSDEV_ATTR(pmc3, 0600, show_pmc3, store_pmc3),
_SYSDEV_ATTR(pmc4, 0600, show_pmc4, store_pmc4),
_SYSDEV_ATTR(pmc5, 0600, show_pmc5, store_pmc5),
_SYSDEV_ATTR(pmc6, 0600, show_pmc6, store_pmc6),
+#ifdef CONFIG_PPC64
_SYSDEV_ATTR(pmc7, 0600, show_pmc7, store_pmc7),
_SYSDEV_ATTR(pmc8, 0600, show_pmc8, store_pmc8),
+#endif
};
+#ifdef HAS_PPC_PMC_PA6T
static struct sysdev_attribute pa6t_attrs[] = {
_SYSDEV_ATTR(mmcr0, 0600, show_mmcr0, store_mmcr0),
_SYSDEV_ATTR(mmcr1, 0600, show_mmcr1, store_mmcr1),
@@ -298,6 +340,8 @@ static struct sysdev_attribute pa6t_attrs[] = {
_SYSDEV_ATTR(tsr3, 0600, show_tsr3, store_tsr3),
#endif /* CONFIG_DEBUG_KERNEL */
};
+#endif /* HAS_PPC_PMC_PA6T */
+#endif /* HAS_PPC_PMC_CLASSIC */
struct cache_desc {
struct kobject kobj;
@@ -588,23 +632,36 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
struct sysdev_attribute *attrs, *pmc_attrs;
int i, nattrs;
+#ifdef CONFIG_PPC64
if (!firmware_has_feature(FW_FEATURE_ISERIES) &&
cpu_has_feature(CPU_FTR_SMT))
sysdev_create_file(s, &attr_smt_snooze_delay);
+#endif
/* PMC stuff */
switch (cur_cpu_spec->pmc_type) {
+#ifdef HAS_PPC_PMC_IBM
case PPC_PMC_IBM:
attrs = ibm_common_attrs;
nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
- pmc_attrs = ibm_pmc_attrs;
+ pmc_attrs = classic_pmc_attrs;
break;
+#endif /* HAS_PPC_PMC_IBM */
+#ifdef HAS_PPC_PMC_G4
+ case PPC_PMC_G4:
+ attrs = g4_common_attrs;
+ nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = classic_pmc_attrs;
+ break;
+#endif /* HAS_PPC_PMC_G4 */
+#ifdef HAS_PPC_PMC_PA6T
case PPC_PMC_PA6T:
/* PA Semi starts counting at PMC0 */
attrs = pa6t_attrs;
nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
pmc_attrs = NULL;
break;
+#endif /* HAS_PPC_PMC_PA6T */
default:
attrs = NULL;
nattrs = 0;
@@ -618,6 +675,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
sysdev_create_file(s, &pmc_attrs[i]);
+#ifdef CONFIG_PPC64
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_create_file(s, &attr_mmcra);
@@ -629,6 +687,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_create_file(s, &attr_dscr);
+#endif /* CONFIG_PPC64 */
create_cache_info(s);
}
@@ -641,16 +700,9 @@ static void remove_cache_info(struct sys_device *sysdev)
int cpu = sysdev->id;
cache_desc = per_cpu(cache_desc, cpu);
- if (cache_desc != NULL) {
- sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr);
- sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr);
- sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr);
- sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr);
- sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr);
- sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr);
-
+ if (cache_desc != NULL)
kobject_put(&cache_desc->kobj);
- }
+
cache_toplevel = per_cpu(cache_toplevel, cpu);
if (cache_toplevel != NULL)
kobject_put(cache_toplevel);
@@ -671,17 +723,28 @@ static void unregister_cpu_online(unsigned int cpu)
/* PMC stuff */
switch (cur_cpu_spec->pmc_type) {
+#ifdef HAS_PPC_PMC_IBM
case PPC_PMC_IBM:
attrs = ibm_common_attrs;
nattrs = sizeof(ibm_common_attrs) / sizeof(struct sysdev_attribute);
- pmc_attrs = ibm_pmc_attrs;
+ pmc_attrs = classic_pmc_attrs;
+ break;
+#endif /* HAS_PPC_PMC_IBM */
+#ifdef HAS_PPC_PMC_G4
+ case PPC_PMC_G4:
+ attrs = g4_common_attrs;
+ nattrs = sizeof(g4_common_attrs) / sizeof(struct sysdev_attribute);
+ pmc_attrs = classic_pmc_attrs;
break;
+#endif /* HAS_PPC_PMC_G4 */
+#ifdef HAS_PPC_PMC_PA6T
case PPC_PMC_PA6T:
/* PA Semi starts counting at PMC0 */
attrs = pa6t_attrs;
nattrs = sizeof(pa6t_attrs) / sizeof(struct sysdev_attribute);
pmc_attrs = NULL;
break;
+#endif /* HAS_PPC_PMC_PA6T */
default:
attrs = NULL;
nattrs = 0;
@@ -695,6 +758,7 @@ static void unregister_cpu_online(unsigned int cpu)
for (i = 0; i < cur_cpu_spec->num_pmcs; i++)
sysdev_remove_file(s, &pmc_attrs[i]);
+#ifdef CONFIG_PPC64
if (cpu_has_feature(CPU_FTR_MMCRA))
sysdev_remove_file(s, &attr_mmcra);
@@ -706,6 +770,7 @@ static void unregister_cpu_online(unsigned int cpu)
if (cpu_has_feature(CPU_FTR_DSCR))
sysdev_remove_file(s, &attr_dscr);
+#endif /* CONFIG_PPC64 */
remove_cache_info(s);
}
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c
index 2750fbab197..434c92a85c0 100644
--- a/arch/powerpc/kernel/vio.c
+++ b/arch/powerpc/kernel/vio.c
@@ -1232,7 +1232,7 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node)
else
viodev->dev.archdata.dma_ops = &dma_iommu_ops;
viodev->dev.archdata.dma_data = vio_build_iommu_table(viodev);
- viodev->dev.archdata.numa_node = of_node_to_nid(of_node);
+ set_dev_node(&viodev->dev, of_node_to_nid(of_node));
/* init generic 'struct device' fields: */
viodev->dev.parent = &vio_bus_device.dev;
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 9f6c1ca1739..b39c27ed791 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -187,6 +187,24 @@ SECTIONS
*(.machine.desc)
__machine_desc_end = . ;
}
+ . = ALIGN(8);
+ .dynsym : AT(ADDR(.dynsym) - LOAD_OFFSET) { *(.dynsym) }
+ .dynstr : AT(ADDR(.dynstr) - LOAD_OFFSET) { *(.dynstr) }
+ .dynamic : AT(ADDR(.dynamic) - LOAD_OFFSET)
+ {
+ __dynamic_start = .;
+ *(.dynamic)
+ }
+ .hash : AT(ADDR(.hash) - LOAD_OFFSET) { *(.hash) }
+ .interp : AT(ADDR(.interp) - LOAD_OFFSET) { *(.interp) }
+ .rela.dyn : AT(ADDR(.rela.dyn) - LOAD_OFFSET)
+ {
+ __rela_dyn_start = .;
+ *(.rela*)
+ }
+
+ /* Fake ELF header containing RPA note; for addnote */
+ .fakeelf : AT(ADDR(.fakeelf) - LOAD_OFFSET) { *(.fakeelf) }
/* freed after init ends here */
. = ALIGN(PAGE_SIZE);
diff --git a/arch/powerpc/lib/copypage_64.S b/arch/powerpc/lib/copypage_64.S
index f9837f44ac0..75f3267fdc3 100644
--- a/arch/powerpc/lib/copypage_64.S
+++ b/arch/powerpc/lib/copypage_64.S
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Paul Mackerras, IBM Corp.
+ * Copyright (C) 2008 Mark Nelson, IBM Corp.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -8,112 +8,100 @@
*/
#include <asm/processor.h>
#include <asm/ppc_asm.h>
+#include <asm/asm-offsets.h>
+
+ .section ".toc","aw"
+PPC64_CACHES:
+ .tc ppc64_caches[TC],ppc64_caches
+ .section ".text"
+
_GLOBAL(copy_4K_page)
- std r31,-8(1)
- std r30,-16(1)
- std r29,-24(1)
- std r28,-32(1)
- std r27,-40(1)
- std r26,-48(1)
- std r25,-56(1)
- std r24,-64(1)
- std r23,-72(1)
- std r22,-80(1)
- std r21,-88(1)
- std r20,-96(1)
- li r5,4096/32 - 1
+ li r5,4096 /* 4K page size */
+BEGIN_FTR_SECTION
+ ld r10,PPC64_CACHES@toc(r2)
+ lwz r11,DCACHEL1LOGLINESIZE(r10) /* log2 of cache line size */
+ lwz r12,DCACHEL1LINESIZE(r10) /* get cache line size */
+ li r9,0
+ srd r8,r5,r11
+
+ mtctr r8
+setup:
+ dcbt r9,r4
+ dcbz r9,r3
+ add r9,r9,r12
+ bdnz setup
+END_FTR_SECTION_IFSET(CPU_FTR_CP_USE_DCBTZ)
addi r3,r3,-8
- li r12,5
-0: addi r5,r5,-24
- mtctr r12
- ld r22,640(4)
- ld r21,512(4)
- ld r20,384(4)
- ld r11,256(4)
- ld r9,128(4)
- ld r7,0(4)
- ld r25,648(4)
- ld r24,520(4)
- ld r23,392(4)
- ld r10,264(4)
- ld r8,136(4)
- ldu r6,8(4)
- cmpwi r5,24
-1: std r22,648(3)
- std r21,520(3)
- std r20,392(3)
- std r11,264(3)
- std r9,136(3)
- std r7,8(3)
- ld r28,648(4)
- ld r27,520(4)
- ld r26,392(4)
- ld r31,264(4)
- ld r30,136(4)
- ld r29,8(4)
- std r25,656(3)
- std r24,528(3)
- std r23,400(3)
- std r10,272(3)
- std r8,144(3)
- std r6,16(3)
- ld r22,656(4)
- ld r21,528(4)
- ld r20,400(4)
- ld r11,272(4)
- ld r9,144(4)
- ld r7,16(4)
- std r28,664(3)
- std r27,536(3)
- std r26,408(3)
- std r31,280(3)
- std r30,152(3)
- stdu r29,24(3)
- ld r25,664(4)
- ld r24,536(4)
- ld r23,408(4)
- ld r10,280(4)
- ld r8,152(4)
- ldu r6,24(4)
+ srdi r8,r5,7 /* page is copied in 128 byte strides */
+ addi r8,r8,-1 /* one stride copied outside loop */
+
+ mtctr r8
+
+ ld r5,0(r4)
+ ld r6,8(r4)
+ ld r7,16(r4)
+ ldu r8,24(r4)
+1: std r5,8(r3)
+ ld r9,8(r4)
+ std r6,16(r3)
+ ld r10,16(r4)
+ std r7,24(r3)
+ ld r11,24(r4)
+ std r8,32(r3)
+ ld r12,32(r4)
+ std r9,40(r3)
+ ld r5,40(r4)
+ std r10,48(r3)
+ ld r6,48(r4)
+ std r11,56(r3)
+ ld r7,56(r4)
+ std r12,64(r3)
+ ld r8,64(r4)
+ std r5,72(r3)
+ ld r9,72(r4)
+ std r6,80(r3)
+ ld r10,80(r4)
+ std r7,88(r3)
+ ld r11,88(r4)
+ std r8,96(r3)
+ ld r12,96(r4)
+ std r9,104(r3)
+ ld r5,104(r4)
+ std r10,112(r3)
+ ld r6,112(r4)
+ std r11,120(r3)
+ ld r7,120(r4)
+ stdu r12,128(r3)
+ ldu r8,128(r4)
bdnz 1b
- std r22,648(3)
- std r21,520(3)
- std r20,392(3)
- std r11,264(3)
- std r9,136(3)
- std r7,8(3)
- addi r4,r4,640
- addi r3,r3,648
- bge 0b
- mtctr r5
- ld r7,0(4)
- ld r8,8(4)
- ldu r9,16(4)
-3: ld r10,8(4)
- std r7,8(3)
- ld r7,16(4)
- std r8,16(3)
- ld r8,24(4)
- std r9,24(3)
- ldu r9,32(4)
- stdu r10,32(3)
- bdnz 3b
-4: ld r10,8(4)
- std r7,8(3)
- std r8,16(3)
- std r9,24(3)
- std r10,32(3)
-9: ld r20,-96(1)
- ld r21,-88(1)
- ld r22,-80(1)
- ld r23,-72(1)
- ld r24,-64(1)
- ld r25,-56(1)
- ld r26,-48(1)
- ld r27,-40(1)
- ld r28,-32(1)
- ld r29,-24(1)
- ld r30,-16(1)
- ld r31,-8(1)
+
+ std r5,8(r3)
+ ld r9,8(r4)
+ std r6,16(r3)
+ ld r10,16(r4)
+ std r7,24(r3)
+ ld r11,24(r4)
+ std r8,32(r3)
+ ld r12,32(r4)
+ std r9,40(r3)
+ ld r5,40(r4)
+ std r10,48(r3)
+ ld r6,48(r4)
+ std r11,56(r3)
+ ld r7,56(r4)
+ std r12,64(r3)
+ ld r8,64(r4)
+ std r5,72(r3)
+ ld r9,72(r4)
+ std r6,80(r3)
+ ld r10,80(r4)
+ std r7,88(r3)
+ ld r11,88(r4)
+ std r8,96(r3)
+ ld r12,96(r4)
+ std r9,104(r3)
+ std r10,112(r3)
+ std r11,120(r3)
+ std r12,128(r3)
blr
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c
index 5d83907f659..31734c0969c 100644
--- a/arch/powerpc/lib/dma-noncoherent.c
+++ b/arch/powerpc/lib/dma-noncoherent.c
@@ -203,7 +203,7 @@ __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp)
/*
* Set the "dma handle"
*/
- *handle = page_to_bus(page);
+ *handle = page_to_phys(page);
do {
BUG_ON(!pte_none(*pte));
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
index 29bc9126241..03aa98dd9f0 100644
--- a/arch/powerpc/math-emu/Makefile
+++ b/arch/powerpc/math-emu/Makefile
@@ -4,13 +4,14 @@ obj-y := math.o fmr.o lfd.o stfd.o
obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
fctiw.o fctiwz.o fdiv.o fdivs.o \
fmadd.o fmadds.o fmsub.o fmsubs.o \
- fmul.o fmuls.o fnabs.o fneg.o types.o \
+ fmul.o fmuls.o fnabs.o fneg.o \
fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
fres.o frsp.o frsqrte.o fsel.o lfs.o \
fsqrt.o fsqrts.o fsub.o fsubs.o \
mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
- mtfsf.o mtfsfi.o stfiwx.o stfs.o \
- udivmodti4.o
+ mtfsf.o mtfsfi.o stfiwx.o stfs.o
CFLAGS_fabs.o = -fno-builtin-fabs
CFLAGS_math.o = -fno-builtin-fabs
+
+EXTRA_CFLAGS = -I. -Iinclude/math-emu -w
diff --git a/arch/powerpc/math-emu/double.h b/arch/powerpc/math-emu/double.h
deleted file mode 100644
index ffba8b67f05..00000000000
--- a/arch/powerpc/math-emu/double.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Definitions for IEEE Double Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid. Go buy yourself a real computer."
-#endif
-
-#if _FP_W_TYPE_SIZE < 64
-#define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE)
-#else
-#define _FP_FRACTBITS_D _FP_W_TYPE_SIZE
-#endif
-
-#define _FP_FRACBITS_D 53
-#define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D)
-#define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D)
-#define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D)
-#define _FP_EXPBITS_D 11
-#define _FP_EXPBIAS_D 1023
-#define _FP_EXPMAX_D 2047
-
-#define _FP_QNANBIT_D \
- ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE))
-#define _FP_IMPLBIT_D \
- ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE))
-#define _FP_OVERFLOW_D \
- ((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE))
-
-#if _FP_W_TYPE_SIZE < 64
-
-union _FP_UNION_D
-{
- double flt;
- struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
- unsigned sign : 1;
- unsigned exp : _FP_EXPBITS_D;
- unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
- unsigned frac0 : _FP_W_TYPE_SIZE;
-#else
- unsigned frac0 : _FP_W_TYPE_SIZE;
- unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
- unsigned exp : _FP_EXPBITS_D;
- unsigned sign : 1;
-#endif
- } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X) _FP_DECL(2,X)
-#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val)
-#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X)
-
-#define FP_UNPACK_D(X,val) \
- do { \
- _FP_UNPACK_RAW_2(D,X,val); \
- _FP_UNPACK_CANONICAL(D,2,X); \
- } while (0)
-
-#define FP_PACK_D(val,X) \
- do { \
- _FP_PACK_CANONICAL(D,2,X); \
- _FP_PACK_RAW_2(D,val,X); \
- } while (0)
-
-#define FP_NEG_D(R,X) _FP_NEG(D,2,R,X)
-#define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y)
-#define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y)
-#define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y)
-#define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y)
-#define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X)
-
-#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt)
-
-#else
-
-union _FP_UNION_D
-{
- double flt;
- struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
- unsigned sign : 1;
- unsigned exp : _FP_EXPBITS_D;
- unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
-#else
- unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
- unsigned exp : _FP_EXPBITS_D;
- unsigned sign : 1;
-#endif
- } bits __attribute__((packed));
-};
-
-#define FP_DECL_D(X) _FP_DECL(1,X)
-#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val)
-#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X)
-
-#define FP_UNPACK_D(X,val) \
- do { \
- _FP_UNPACK_RAW_1(D,X,val); \
- _FP_UNPACK_CANONICAL(D,1,X); \
- } while (0)
-
-#define FP_PACK_D(val,X) \
- do { \
- _FP_PACK_CANONICAL(D,1,X); \
- _FP_PACK_RAW_1(D,val,X); \
- } while (0)
-
-#define FP_NEG_D(R,X) _FP_NEG(D,1,R,X)
-#define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y)
-#define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y)
-#define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y)
-#define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y)
-#define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X)
-
-/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
- the target machine. */
-
-#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un)
-#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y)
-
-#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg)
-#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt)
-
-#endif /* W_TYPE_SIZE < 64 */
diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c
index 7befbbf2c33..04d3b4aa32c 100644
--- a/arch/powerpc/math-emu/fadd.c
+++ b/arch/powerpc/math-emu/fadd.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fadd(void *frD, void *frA, void *frB)
@@ -11,28 +12,28 @@ fadd(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
#endif
- if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
- ret |= EFLAG_VXISI;
-
FP_ADD_D(R, A, B);
#ifdef DEBUG
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c
index 2b346b38b48..5930f40a868 100644
--- a/arch/powerpc/math-emu/fadds.c
+++ b/arch/powerpc/math-emu/fadds.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fadds(void *frD, void *frA, void *frB)
@@ -12,28 +13,27 @@ fadds(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
- int ret = 0;
+ FP_DECL_EX;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
#endif
- if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
- ret |= EFLAG_VXISI;
-
FP_ADD_D(R, A, B);
#ifdef DEBUG
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c
index 36d689044c6..b5dc4498cd7 100644
--- a/arch/powerpc/math-emu/fcmpo.c
+++ b/arch/powerpc/math-emu/fcmpo.c
@@ -2,14 +2,16 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fcmpo(u32 *ccr, int crfD, void *frA, void *frB)
{
FP_DECL_D(A);
FP_DECL_D(B);
+ FP_DECL_EX;
int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
long cmp;
int ret = 0;
@@ -18,8 +20,8 @@ fcmpo(u32 *ccr, int crfD, void *frA, void *frB)
printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
diff --git a/arch/powerpc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c
index 53d93894f2a..d4fb1babc6a 100644
--- a/arch/powerpc/math-emu/fcmpu.c
+++ b/arch/powerpc/math-emu/fcmpu.c
@@ -2,14 +2,16 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fcmpu(u32 *ccr, int crfD, void *frA, void *frB)
{
FP_DECL_D(A);
FP_DECL_D(B);
+ FP_DECL_EX;
int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
long cmp;
@@ -17,8 +19,8 @@ fcmpu(u32 *ccr, int crfD, void *frA, void *frB)
printk("%s: %p (%08x) %d %p %p\n", __func__, ccr, *ccr, crfD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
diff --git a/arch/powerpc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c
index fcd7a95e021..f694440ddc0 100644
--- a/arch/powerpc/math-emu/fctiw.c
+++ b/arch/powerpc/math-emu/fctiw.c
@@ -2,16 +2,18 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fctiw(u32 *frD, void *frB)
{
FP_DECL_D(B);
+ FP_DECL_EX;
unsigned int r;
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(B, frB);
FP_TO_INT_D(r, B, 32, 1);
frD[1] = r;
diff --git a/arch/powerpc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c
index 1514d59e146..71e782fd4fe 100644
--- a/arch/powerpc/math-emu/fctiwz.c
+++ b/arch/powerpc/math-emu/fctiwz.c
@@ -2,13 +2,15 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fctiwz(u32 *frD, void *frB)
{
FP_DECL_D(B);
+ FP_DECL_EX;
u32 fpscr;
unsigned int r;
@@ -16,7 +18,7 @@ fctiwz(u32 *frD, void *frB)
__FPU_FPSCR &= ~(3);
__FPU_FPSCR |= FP_RND_ZERO;
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(B, frB);
FP_TO_INT_D(r, B, 32, 1);
frD[1] = r;
diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c
index 18a20fe396b..2db15097d98 100644
--- a/arch/powerpc/math-emu/fdiv.c
+++ b/arch/powerpc/math-emu/fdiv.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fdiv(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fdiv(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -49,5 +51,7 @@ fdiv(void *frD, void *frA, void *frB)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c
index 24feed689c3..797f6a9a20b 100644
--- a/arch/powerpc/math-emu/fdivs.c
+++ b/arch/powerpc/math-emu/fdivs.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fdivs(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fdivs(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -51,5 +53,7 @@ fdivs(void *frD, void *frA, void *frB)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c
index dedb465fdc6..925313aa6f8 100644
--- a/arch/powerpc/math-emu/fmadd.c
+++ b/arch/powerpc/math-emu/fmadd.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fmadd(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fmadd(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -44,5 +46,7 @@ fmadd(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c
index 6bbb56d5502..aea80ef7939 100644
--- a/arch/powerpc/math-emu/fmadds.c
+++ b/arch/powerpc/math-emu/fmadds.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fmadds(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fmadds(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -45,5 +47,7 @@ fmadds(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c
index f311e2c7e67..a644d525fca 100644
--- a/arch/powerpc/math-emu/fmsub.c
+++ b/arch/powerpc/math-emu/fmsub.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fmsub(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fmsub(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -47,5 +49,7 @@ fmsub(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c
index 81a716d3ee2..2fdeeb9bb56 100644
--- a/arch/powerpc/math-emu/fmsubs.c
+++ b/arch/powerpc/math-emu/fmsubs.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fmsubs(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fmsubs(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -48,5 +50,7 @@ fmsubs(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c
index 2f3d32784a0..391fd17d344 100644
--- a/arch/powerpc/math-emu/fmul.c
+++ b/arch/powerpc/math-emu/fmul.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fmul(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fmul(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
@@ -38,5 +40,7 @@ fmul(void *frD, void *frA, void *frB)
R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c
index 962b5883f78..2d3ec5f7da2 100644
--- a/arch/powerpc/math-emu/fmuls.c
+++ b/arch/powerpc/math-emu/fmuls.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fmuls(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fmuls(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
@@ -39,5 +41,7 @@ fmuls(void *frD, void *frA, void *frB)
R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c
index 8cf7827c4fb..2497b86494e 100644
--- a/arch/powerpc/math-emu/fnmadd.c
+++ b/arch/powerpc/math-emu/fnmadd.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fnmadd(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fnmadd(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -47,5 +49,7 @@ fnmadd(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c
index f1c4f0f0d80..ee9d71e0b37 100644
--- a/arch/powerpc/math-emu/fnmadds.c
+++ b/arch/powerpc/math-emu/fnmadds.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fnmadds(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fnmadds(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -48,5 +50,7 @@ fnmadds(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c
index 98944e6e260..3885a77acc9 100644
--- a/arch/powerpc/math-emu/fnmsub.c
+++ b/arch/powerpc/math-emu/fnmsub.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fnmsub(void *frD, void *frA, void *frB, void *frC)
@@ -13,15 +14,16 @@ fnmsub(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -50,5 +52,7 @@ fnmsub(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c
index b20f4eb63fb..f835dfeb0fd 100644
--- a/arch/powerpc/math-emu/fnmsubs.c
+++ b/arch/powerpc/math-emu/fnmsubs.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fnmsubs(void *frD, void *frA, void *frB, void *frC)
@@ -14,15 +15,16 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC)
FP_DECL_D(B);
FP_DECL_D(C);
FP_DECL_D(T);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
- __FP_UNPACK_D(C, frC);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
+ FP_UNPACK_DP(C, frC);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -51,5 +53,7 @@ fnmsubs(void *frD, void *frA, void *frB, void *frC)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c
index 724ccbc0468..ddcc14664b1 100644
--- a/arch/powerpc/math-emu/frsp.c
+++ b/arch/powerpc/math-emu/frsp.c
@@ -2,24 +2,28 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
frsp(void *frD, void *frB)
{
FP_DECL_D(B);
+ FP_DECL_EX;
#ifdef DEBUG
printk("%s: D %p, B %p\n", __func__, frD, frB);
#endif
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
#endif
- return __FP_PACK_DS(frD, B);
+ __FP_PACK_DS(frD, B);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c
index ecb5f28eb1f..1b0c1449803 100644
--- a/arch/powerpc/math-emu/fsel.c
+++ b/arch/powerpc/math-emu/fsel.c
@@ -2,19 +2,21 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fsel(u32 *frD, void *frA, u32 *frB, u32 *frC)
{
FP_DECL_D(A);
+ FP_DECL_EX;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frA, frB, frC);
#endif
- __FP_UNPACK_D(A, frA);
+ FP_UNPACK_DP(A, frA);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c
index 38ec2b752e9..3e90072693a 100644
--- a/arch/powerpc/math-emu/fsqrt.c
+++ b/arch/powerpc/math-emu/fsqrt.c
@@ -2,21 +2,23 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fsqrt(void *frD, void *frB)
{
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frB);
#endif
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
@@ -33,5 +35,7 @@ fsqrt(void *frD, void *frB)
printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c
index 335263e06ee..2843be986e2 100644
--- a/arch/powerpc/math-emu/fsqrts.c
+++ b/arch/powerpc/math-emu/fsqrts.c
@@ -2,22 +2,24 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fsqrts(void *frD, void *frB)
{
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p %p\n", __func__, frD, frB);
#endif
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
@@ -34,5 +36,7 @@ fsqrts(void *frD, void *frB)
printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c
index 208d20fc52a..78b09446a0e 100644
--- a/arch/powerpc/math-emu/fsub.c
+++ b/arch/powerpc/math-emu/fsub.c
@@ -2,8 +2,9 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
int
fsub(void *frD, void *frA, void *frB)
@@ -11,14 +12,15 @@ fsub(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -37,5 +39,7 @@ fsub(void *frD, void *frA, void *frB)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_D(frD, R));
+ __FP_PACK_D(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c
index 0e61b808c44..d3bf90863cf 100644
--- a/arch/powerpc/math-emu/fsubs.c
+++ b/arch/powerpc/math-emu/fsubs.c
@@ -2,9 +2,10 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
fsubs(void *frD, void *frA, void *frB)
@@ -12,14 +13,15 @@ fsubs(void *frD, void *frA, void *frB)
FP_DECL_D(A);
FP_DECL_D(B);
FP_DECL_D(R);
+ FP_DECL_EX;
int ret = 0;
#ifdef DEBUG
printk("%s: %p %p %p\n", __func__, frD, frA, frB);
#endif
- __FP_UNPACK_D(A, frA);
- __FP_UNPACK_D(B, frB);
+ FP_UNPACK_DP(A, frA);
+ FP_UNPACK_DP(B, frB);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -38,5 +40,7 @@ fsubs(void *frD, void *frA, void *frB)
printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return (ret | __FP_PACK_DS(frD, R));
+ __FP_PACK_DS(frD, R);
+
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c
index 6ec90b57c61..79ac76d596c 100644
--- a/arch/powerpc/math-emu/lfd.c
+++ b/arch/powerpc/math-emu/lfd.c
@@ -2,8 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "sfp-machine.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/double.h>
int
lfd(void *frD, void *ea)
diff --git a/arch/powerpc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c
index 6f18ebe3a7f..434ed27be8d 100644
--- a/arch/powerpc/math-emu/lfs.c
+++ b/arch/powerpc/math-emu/lfs.c
@@ -2,15 +2,17 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
lfs(void *frD, void *ea)
{
FP_DECL_D(R);
FP_DECL_S(A);
+ FP_DECL_EX;
float f;
#ifdef DEBUG
@@ -20,7 +22,7 @@ lfs(void *frD, void *ea)
if (copy_from_user(&f, ea, sizeof(float)))
return -EFAULT;
- __FP_UNPACK_S(A, &f);
+ FP_UNPACK_S(A, f);
#ifdef DEBUG
printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c,
@@ -33,5 +35,12 @@ lfs(void *frD, void *ea)
printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
#endif
- return __FP_PACK_D(frD, R);
+ if (R_c == FP_CLS_NAN) {
+ R_e = _FP_EXPMAX_D;
+ _FP_PACK_RAW_2_P(D, frD, R);
+ } else {
+ __FP_PACK_D(frD, R);
+ }
+
+ return 0;
}
diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c
index 29e545e0272..164d55935bd 100644
--- a/arch/powerpc/math-emu/math.c
+++ b/arch/powerpc/math-emu/math.c
@@ -8,8 +8,8 @@
#include <asm/uaccess.h>
#include <asm/reg.h>
-#include "sfp-machine.h"
-#include "double.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/double.h>
#define FLOATFUNC(x) extern int x(void *, void *, void *, void *)
@@ -168,6 +168,8 @@ record_exception(struct pt_regs *regs, int eflag)
fpscr |= FPSCR_ZX;
if (eflag & EFLAG_INEXACT)
fpscr |= FPSCR_XX;
+ if (eflag & EFLAG_INVALID)
+ fpscr |= FPSCR_VX;
if (eflag & EFLAG_VXSNAN)
fpscr |= FPSCR_VXSNAN;
if (eflag & EFLAG_VXISI)
@@ -188,7 +190,7 @@ record_exception(struct pt_regs *regs, int eflag)
fpscr |= FPSCR_VXCVI;
}
- fpscr &= ~(FPSCR_VX);
+// fpscr &= ~(FPSCR_VX);
if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
diff --git a/arch/powerpc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c
index 41ba247faf8..e948d5708e2 100644
--- a/arch/powerpc/math-emu/mcrfs.c
+++ b/arch/powerpc/math-emu/mcrfs.c
@@ -2,7 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mcrfs(u32 *ccr, u32 crfD, u32 crfS)
diff --git a/arch/powerpc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c
index b0e2106e6eb..5526cf96ede 100644
--- a/arch/powerpc/math-emu/mffs.c
+++ b/arch/powerpc/math-emu/mffs.c
@@ -2,7 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mffs(u32 *frD)
diff --git a/arch/powerpc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c
index d3062350ea2..bc985585bca 100644
--- a/arch/powerpc/math-emu/mtfsb0.c
+++ b/arch/powerpc/math-emu/mtfsb0.c
@@ -2,7 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mtfsb0(int crbD)
diff --git a/arch/powerpc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c
index 2e948704b56..fe6ed5ac85b 100644
--- a/arch/powerpc/math-emu/mtfsb1.c
+++ b/arch/powerpc/math-emu/mtfsb1.c
@@ -2,7 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mtfsb1(int crbD)
diff --git a/arch/powerpc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c
index 48014d8e3af..dbce92e4f04 100644
--- a/arch/powerpc/math-emu/mtfsf.c
+++ b/arch/powerpc/math-emu/mtfsf.c
@@ -2,12 +2,14 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mtfsf(unsigned int FM, u32 *frB)
{
u32 mask;
+ u32 fpscr;
if (FM == 0)
return 0;
@@ -37,6 +39,22 @@ mtfsf(unsigned int FM, u32 *frB)
__FPU_FPSCR &= ~(mask);
__FPU_FPSCR |= (frB[1] & mask);
+ __FPU_FPSCR &= ~(FPSCR_VX);
+ if (__FPU_FPSCR & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
+ FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
+ FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
+ __FPU_FPSCR |= FPSCR_VX;
+
+ fpscr = __FPU_FPSCR;
+ fpscr &= ~(FPSCR_FEX);
+ if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
+ ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
+ ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
+ ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
+ ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
+ fpscr |= FPSCR_FEX;
+ __FPU_FPSCR = fpscr;
+
#ifdef DEBUG
printk("%s: %02x %p: %08lx\n", __func__, FM, frB, __FPU_FPSCR);
#endif
diff --git a/arch/powerpc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c
index 031e2009354..fd2acc26813 100644
--- a/arch/powerpc/math-emu/mtfsfi.c
+++ b/arch/powerpc/math-emu/mtfsfi.c
@@ -2,7 +2,8 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
int
mtfsfi(unsigned int crfD, unsigned int IMM)
diff --git a/arch/powerpc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h
deleted file mode 100644
index c92fa95f562..00000000000
--- a/arch/powerpc/math-emu/op-1.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Basic one-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f
-#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f)
-#define _FP_FRAC_SET_1(X,I) (X##_f = I)
-#define _FP_FRAC_HIGH_1(X) (X##_f)
-#define _FP_FRAC_LOW_1(X) (X##_f)
-#define _FP_FRAC_WORD_1(X,w) (X##_f)
-
-#define _FP_FRAC_ADDI_1(X,I) (X##_f += I)
-#define _FP_FRAC_SLL_1(X,N) \
- do { \
- if (__builtin_constant_p(N) && (N) == 1) \
- X##_f += X##_f; \
- else \
- X##_f <<= (N); \
- } while (0)
-#define _FP_FRAC_SRL_1(X,N) (X##_f >>= N)
-
-/* Right shift with sticky-lsb. */
-#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz)
-
-#define __FP_FRAC_SRS_1(X,N,sz) \
- (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \
- ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0)))
-
-#define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f)
-#define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f)
-#define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0)
-#define _FP_FRAC_ZEROP_1(X) (X##_f == 0)
-#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f)
-#define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f)
-#define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f)
-
-#define _FP_ZEROFRAC_1 0
-#define _FP_MINFRAC_1 1
-
-/*
- * Unpack the raw bits of a native fp value. Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_1(fs, X, val) \
- do { \
- union _FP_UNION_##fs _flo; _flo.flt = (val); \
- \
- X##_f = _flo.bits.frac; \
- X##_e = _flo.bits.exp; \
- X##_s = _flo.bits.sign; \
- } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_1(fs, val, X) \
- do { \
- union _FP_UNION_##fs _flo; \
- \
- _flo.bits.frac = X##_f; \
- _flo.bits.exp = X##_e; \
- _flo.bits.sign = X##_s; \
- \
- (val) = _flo.flt; \
- } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the
- multiplication immediately. */
-
-#define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \
- do { \
- R##_f = X##_f * Y##_f; \
- /* Normalize since we know where the msb of the multiplicands \
- were (bit B), we know that the msb of the of the product is \
- at either 2B or 2B-1. */ \
- _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
- } while (0)
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */
-
-#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \
- do { \
- _FP_W_TYPE _Z_f0, _Z_f1; \
- doit(_Z_f1, _Z_f0, X##_f, Y##_f); \
- /* Normalize since we know where the msb of the multiplicands \
- were (bit B), we know that the msb of the of the product is \
- at either 2B or 2B-1. */ \
- _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
- R##_f = _Z_f0; \
- } while (0)
-
-/* Finally, a simple widening multiply algorithm. What fun! */
-
-#define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \
- do { \
- _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \
- \
- /* split the words in half */ \
- _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \
- _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \
- _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \
- _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \
- \
- /* multiply the pieces */ \
- _z_f0 = _xl * _yl; \
- _a_f0 = _xh * _yl; \
- _a_f1 = _xl * _yh; \
- _z_f1 = _xh * _yh; \
- \
- /* reassemble into two full words */ \
- if ((_a_f0 += _a_f1) < _a_f1) \
- _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \
- _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \
- _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \
- _FP_FRAC_ADD_2(_z, _z, _a); \
- \
- /* normalize */ \
- _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \
- R##_f = _z_f0; \
- } while (0)
-
-
-/*
- * Division algorithms:
- */
-
-/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the
- division immediately. Give this macro either _FP_DIV_HELP_imm for
- C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you
- choose will depend on what the compiler does with divrem4. */
-
-#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \
- do { \
- _FP_W_TYPE _q, _r; \
- X##_f <<= (X##_f < Y##_f \
- ? R##_e--, _FP_WFRACBITS_##fs \
- : _FP_WFRACBITS_##fs - 1); \
- doit(_q, _r, X##_f, Y##_f); \
- R##_f = _q | (_r != 0); \
- } while (0)
-
-/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd
- that may be useful in this situation. This first is for a primitive
- that requires normalization, the second for one that does not. Look
- for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */
-
-#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \
- do { \
- _FP_W_TYPE _nh, _nl, _q, _r; \
- \
- /* Normalize Y -- i.e. make the most significant bit set. */ \
- Y##_f <<= _FP_WFRACXBITS_##fs - 1; \
- \
- /* Shift X op correspondingly high, that is, up one full word. */ \
- if (X##_f <= Y##_f) \
- { \
- _nl = 0; \
- _nh = X##_f; \
- } \
- else \
- { \
- R##_e++; \
- _nl = X##_f << (_FP_W_TYPE_SIZE-1); \
- _nh = X##_f >> 1; \
- } \
- \
- udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \
- R##_f = _q | (_r != 0); \
- } while (0)
-
-#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \
- do { \
- _FP_W_TYPE _nh, _nl, _q, _r; \
- if (X##_f < Y##_f) \
- { \
- R##_e--; \
- _nl = X##_f << _FP_WFRACBITS_##fs; \
- _nh = X##_f >> _FP_WFRACXBITS_##fs; \
- } \
- else \
- { \
- _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \
- _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \
- } \
- udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \
- R##_f = _q | (_r != 0); \
- } while (0)
-
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
-
-#define _FP_SQRT_MEAT_1(R, S, T, X, q) \
- do { \
- while (q) \
- { \
- T##_f = S##_f + q; \
- if (T##_f <= X##_f) \
- { \
- S##_f = T##_f + q; \
- X##_f -= T##_f; \
- R##_f += q; \
- } \
- _FP_FRAC_SLL_1(X, 1); \
- q >>= 1; \
- } \
- } while (0)
-
-/*
- * Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f)
-#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r)
-
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \
- do { \
- D##_f = S##_f; \
- if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \
- _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \
- _FP_WFRACBITS_##sfs); \
- else \
- D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \
- } while (0)
diff --git a/arch/powerpc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h
deleted file mode 100644
index 7d6f17cc292..00000000000
--- a/arch/powerpc/math-emu/op-2.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Basic two-word fraction declaration and manipulation.
- */
-
-#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1
-#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1)
-#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I)
-#define _FP_FRAC_HIGH_2(X) (X##_f1)
-#define _FP_FRAC_LOW_2(X) (X##_f0)
-#define _FP_FRAC_WORD_2(X,w) (X##_f##w)
-
-#define _FP_FRAC_SLL_2(X,N) \
- do { \
- if ((N) < _FP_W_TYPE_SIZE) \
- { \
- if (__builtin_constant_p(N) && (N) == 1) \
- { \
- X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \
- X##_f0 += X##_f0; \
- } \
- else \
- { \
- X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \
- X##_f0 <<= (N); \
- } \
- } \
- else \
- { \
- X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \
- X##_f0 = 0; \
- } \
- } while (0)
-
-#define _FP_FRAC_SRL_2(X,N) \
- do { \
- if ((N) < _FP_W_TYPE_SIZE) \
- { \
- X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \
- X##_f1 >>= (N); \
- } \
- else \
- { \
- X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \
- X##_f1 = 0; \
- } \
- } while (0)
-
-/* Right shift with sticky-lsb. */
-#define _FP_FRAC_SRS_2(X,N,sz) \
- do { \
- if ((N) < _FP_W_TYPE_SIZE) \
- { \
- X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \
- (__builtin_constant_p(N) && (N) == 1 \
- ? X##_f0 & 1 \
- : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \
- X##_f1 >>= (N); \
- } \
- else \
- { \
- X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \
- (((X##_f1 << (2 * _FP_W_TYPE_SIZE - (N))) | \
- X##_f0) != 0)); \
- X##_f1 = 0; \
- } \
- } while (0)
-
-#define _FP_FRAC_ADDI_2(X,I) \
- __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
-
-#define _FP_FRAC_ADD_2(R,X,Y) \
- __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_SUB_2(R,X,Y) \
- __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
-
-#define _FP_FRAC_CLZ_2(R,X) \
- do { \
- if (X##_f1) \
- __FP_CLZ(R,X##_f1); \
- else \
- { \
- __FP_CLZ(R,X##_f0); \
- R += _FP_W_TYPE_SIZE; \
- } \
- } while(0)
-
-/* Predicates */
-#define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0)
-#define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0)
-#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs)
-#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
-#define _FP_FRAC_GT_2(X, Y) \
- ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
-#define _FP_FRAC_GE_2(X, Y) \
- ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0))
-
-#define _FP_ZEROFRAC_2 0, 0
-#define _FP_MINFRAC_2 0, 1
-
-/*
- * Internals
- */
-
-#define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1)
-
-#define __FP_CLZ_2(R, xh, xl) \
- do { \
- if (xh) \
- __FP_CLZ(R,xl); \
- else \
- { \
- __FP_CLZ(R,xl); \
- R += _FP_W_TYPE_SIZE; \
- } \
- } while(0)
-
-#if 0
-
-#ifndef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i) \
- (xh += ((xl += i) < i))
-#endif
-#ifndef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \
- (rh = xh + yh + ((rl = xl + yl) < xl))
-#endif
-#ifndef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \
- (rh = xh - yh - ((rl = xl - yl) > xl))
-#endif
-
-#else
-
-#undef __FP_FRAC_ADDI_2
-#define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i)
-#undef __FP_FRAC_ADD_2
-#define __FP_FRAC_ADD_2 add_ssaaaa
-#undef __FP_FRAC_SUB_2
-#define __FP_FRAC_SUB_2 sub_ddmmss
-
-#endif
-
-/*
- * Unpack the raw bits of a native fp value. Do not classify or
- * normalize the data.
- */
-
-#define _FP_UNPACK_RAW_2(fs, X, val) \
- do { \
- union _FP_UNION_##fs _flo; _flo.flt = (val); \
- \
- X##_f0 = _flo.bits.frac0; \
- X##_f1 = _flo.bits.frac1; \
- X##_e = _flo.bits.exp; \
- X##_s = _flo.bits.sign; \
- } while (0)
-
-
-/*
- * Repack the raw bits of a native fp value.
- */
-
-#define _FP_PACK_RAW_2(fs, val, X) \
- do { \
- union _FP_UNION_##fs _flo; \
- \
- _flo.bits.frac0 = X##_f0; \
- _flo.bits.frac1 = X##_f1; \
- _flo.bits.exp = X##_e; \
- _flo.bits.sign = X##_s; \
- \
- (val) = _flo.flt; \
- } while (0)
-
-
-/*
- * Multiplication algorithms:
- */
-
-/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */
-
-#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \
- do { \
- _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \
- \
- doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \
- doit(_b_f1, _b_f0, X##_f0, Y##_f1); \
- doit(_c_f1, _c_f0, X##_f1, Y##_f0); \
- doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \
- \
- __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
- 0, _b_f1, _b_f0, 0, \
- _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
- __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
- 0, _c_f1, _c_f0, 0, \
- _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
- _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
- \
- /* Normalize since we know where the msb of the multiplicands \
- were (bit B), we know that the msb of the of the product is \
- at either 2B or 2B-1. */ \
- _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
- R##_f0 = _FP_FRAC_WORD_4(_z,0); \
- R##_f1 = _FP_FRAC_WORD_4(_z,1); \
- } while (0)
-
-/* This next macro appears to be totally broken. Fortunately nowhere
- * seems to use it :-> The problem is that we define _z[4] but
- * then use it in _FP_FRAC_SRS_4, which will attempt to access
- * _z_f[n] which will cause an error. The fix probably involves
- * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998
- */
-#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \
- do { \
- _FP_W_TYPE _x[2], _y[2], _z[4]; \
- _x[0] = X##_f0; _x[1] = X##_f1; \
- _y[0] = Y##_f0; _y[1] = Y##_f1; \
- \
- mpn_mul_n(_z, _x, _y, 2); \
- \
- /* Normalize since we know where the msb of the multiplicands \
- were (bit B), we know that the msb of the of the product is \
- at either 2B or 2B-1. */ \
- _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \
- R##_f0 = _z[0]; \
- R##_f1 = _z[1]; \
- } while (0)
-
-
-/*
- * Division algorithms:
- * This seems to be giving me difficulties -- PMM
- * Look, NetBSD seems to be able to comment algorithms. Can't you?
- * I've thrown printks at the problem.
- * This now appears to work, but I still don't really know why.
- * Also, I don't think the result is properly normalised...
- */
-
-#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y) \
- do { \
- extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], \
- _FP_W_TYPE n1, _FP_W_TYPE n0, \
- _FP_W_TYPE d1, _FP_W_TYPE d0); \
- _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0; \
- _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0; \
- _FP_W_TYPE _rmem[2], _qmem[2]; \
- /* I think this check is to ensure that the result is normalised. \
- * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in \
- * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y. \
- * In this case we tweak things. (this is based on comments in \
- * the NetBSD FPU emulation code. ) \
- * We know X,Y are normalised because we ensure this as part of \
- * the unpacking process. -- PMM \
- */ \
- if (_FP_FRAC_GT_2(X, Y)) \
- { \
-/* R##_e++; */ \
- _n_f3 = X##_f1 >> 1; \
- _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \
- _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \
- _n_f0 = 0; \
- } \
- else \
- { \
- R##_e--; \
- _n_f3 = X##_f1; \
- _n_f2 = X##_f0; \
- _n_f1 = _n_f0 = 0; \
- } \
- \
- /* Normalize, i.e. make the most significant bit of the \
- denominator set. CHANGED: - 1 to nothing -- PMM */ \
- _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */); \
- \
- /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 \
- primitive snagged from libgcc2.c. */ \
- \
- _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1); \
- _q_f1 = _qmem[0]; \
- umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0); \
- _r_f1 = _rmem[0]; \
- _r_f0 = _n_f1; \
- if (_FP_FRAC_GT_2(_m, _r)) \
- { \
- _q_f1--; \
- _FP_FRAC_ADD_2(_r, _r, Y); \
- if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \
- { \
- _q_f1--; \
- _FP_FRAC_ADD_2(_r, _r, Y); \
- } \
- } \
- _FP_FRAC_SUB_2(_r, _r, _m); \
- \
- _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1); \
- _q_f0 = _qmem[0]; \
- umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0); \
- _r_f1 = _rmem[0]; \
- _r_f0 = _n_f0; \
- if (_FP_FRAC_GT_2(_m, _r)) \
- { \
- _q_f0--; \
- _FP_FRAC_ADD_2(_r, _r, Y); \
- if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \
- { \
- _q_f0--; \
- _FP_FRAC_ADD_2(_r, _r, Y); \
- } \
- } \
- _FP_FRAC_SUB_2(_r, _r, _m); \
- \
- R##_f1 = _q_f1; \
- R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0); \
- /* adjust so answer is normalized again. I'm not sure what the \
- * final sz param should be. In practice it's never used since \
- * N is 1 which is always going to be < _FP_W_TYPE_SIZE... \
- */ \
- /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */ \
- } while (0)
-
-
-#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \
- do { \
- _FP_W_TYPE _x[4], _y[2], _z[4]; \
- _y[0] = Y##_f0; _y[1] = Y##_f1; \
- _x[0] = _x[3] = 0; \
- if (_FP_FRAC_GT_2(X, Y)) \
- { \
- R##_e++; \
- _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) | \
- X##_f1 >> (_FP_W_TYPE_SIZE - \
- (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE))); \
- _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE); \
- } \
- else \
- { \
- _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) | \
- X##_f1 >> (_FP_W_TYPE_SIZE - \
- (_FP_WFRACBITS - _FP_W_TYPE_SIZE))); \
- _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE); \
- } \
- \
- (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \
- R##_f1 = _z[1]; \
- R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \
- } while (0)
-
-
-/*
- * Square root algorithms:
- * We have just one right now, maybe Newton approximation
- * should be added for those machines where division is fast.
- */
-
-#define _FP_SQRT_MEAT_2(R, S, T, X, q) \
- do { \
- while (q) \
- { \
- T##_f1 = S##_f1 + q; \
- if (T##_f1 <= X##_f1) \
- { \
- S##_f1 = T##_f1 + q; \
- X##_f1 -= T##_f1; \
- R##_f1 += q; \
- } \
- _FP_FRAC_SLL_2(X, 1); \
- q >>= 1; \
- } \
- q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \
- while (q) \
- { \
- T##_f0 = S##_f0 + q; \
- T##_f1 = S##_f1; \
- if (T##_f1 < X##_f1 || \
- (T##_f1 == X##_f1 && T##_f0 < X##_f0)) \
- { \
- S##_f0 = T##_f0 + q; \
- if (((_FP_WS_TYPE)T##_f0) < 0 && \
- ((_FP_WS_TYPE)S##_f0) >= 0) \
- S##_f1++; \
- _FP_FRAC_SUB_2(X, X, T); \
- R##_f0 += q; \
- } \
- _FP_FRAC_SLL_2(X, 1); \
- q >>= 1; \
- } \
- } while (0)
-
-
-/*
- * Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-
-#define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \
- do { \
- if (rsize <= _FP_W_TYPE_SIZE) \
- r = X##_f0; \
- else \
- { \
- r = X##_f1; \
- r <<= _FP_W_TYPE_SIZE; \
- r += X##_f0; \
- } \
- } while (0)
-
-#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \
- do { \
- X##_f0 = r; \
- X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \
- } while (0)
-
-/*
- * Convert FP values between word sizes
- */
-
-#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \
- do { \
- _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
- _FP_WFRACBITS_##sfs); \
- D##_f = S##_f0; \
- } while (0)
-
-#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \
- do { \
- D##_f0 = S##_f; \
- D##_f1 = 0; \
- _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
- } while (0)
-
diff --git a/arch/powerpc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h
deleted file mode 100644
index c9ae626070d..00000000000
--- a/arch/powerpc/math-emu/op-4.h
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Basic four-word fraction declaration and manipulation.
- *
- * When adding quadword support for 32 bit machines, we need
- * to be a little careful as double multiply uses some of these
- * macros: (in op-2.h)
- * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
- * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
- * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
- * _FP_FRAC_DECL_4: it appears to be broken and is not used
- * anywhere anyway. )
- *
- * I've now fixed all the macros that were here from the sparc64 code.
- * [*none* of the shift macros were correct!] -- PMM 02/1998
- *
- * The only quadword stuff that remains to be coded is:
- * 1) the conversion to/from ints, which requires
- * that we check (in op-common.h) that the following do the right thing
- * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
- * 2) multiply, divide and sqrt, which require:
- * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
- * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
- * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
- * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
- * these; they are used nowhere else. ]
- */
-
-#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4]
-#define _FP_FRAC_COPY_4(D,S) \
- (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \
- D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
-/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
- * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
- * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
- * which just assigns the In values to the array X##_f[].
- * This is why the number of parameters doesn't appear to match
- * at first glance... -- PMM
- */
-#define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I)
-#define _FP_FRAC_HIGH_4(X) (X##_f[3])
-#define _FP_FRAC_LOW_4(X) (X##_f[0])
-#define _FP_FRAC_WORD_4(X,w) (X##_f[w])
-
-#define _FP_FRAC_SLL_4(X,N) \
- do { \
- _FP_I_TYPE _up, _down, _skip, _i; \
- _skip = (N) / _FP_W_TYPE_SIZE; \
- _up = (N) % _FP_W_TYPE_SIZE; \
- _down = _FP_W_TYPE_SIZE - _up; \
- for (_i = 3; _i > _skip; --_i) \
- X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \
-/* bugfixed: was X##_f[_i] <<= _up; -- PMM 02/1998 */ \
- X##_f[_i] = X##_f[0] << _up; \
- for (--_i; _i >= 0; --_i) \
- X##_f[_i] = 0; \
- } while (0)
-
-/* This one was broken too */
-#define _FP_FRAC_SRL_4(X,N) \
- do { \
- _FP_I_TYPE _up, _down, _skip, _i; \
- _skip = (N) / _FP_W_TYPE_SIZE; \
- _down = (N) % _FP_W_TYPE_SIZE; \
- _up = _FP_W_TYPE_SIZE - _down; \
- for (_i = 0; _i < 3-_skip; ++_i) \
- X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
- X##_f[_i] = X##_f[3] >> _down; \
- for (++_i; _i < 4; ++_i) \
- X##_f[_i] = 0; \
- } while (0)
-
-
-/* Right shift with sticky-lsb.
- * What this actually means is that we do a standard right-shift,
- * but that if any of the bits that fall off the right hand side
- * were one then we always set the LSbit.
- */
-#define _FP_FRAC_SRS_4(X,N,size) \
- do { \
- _FP_I_TYPE _up, _down, _skip, _i; \
- _FP_W_TYPE _s; \
- _skip = (N) / _FP_W_TYPE_SIZE; \
- _down = (N) % _FP_W_TYPE_SIZE; \
- _up = _FP_W_TYPE_SIZE - _down; \
- for (_s = _i = 0; _i < _skip; ++_i) \
- _s |= X##_f[_i]; \
- _s |= X##_f[_i] << _up; \
-/* s is now != 0 if we want to set the LSbit */ \
- for (_i = 0; _i < 3-_skip; ++_i) \
- X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
- X##_f[_i] = X##_f[3] >> _down; \
- for (++_i; _i < 4; ++_i) \
- X##_f[_i] = 0; \
- /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
- X##_f[0] |= (_s != 0); \
- } while (0)
-
-#define _FP_FRAC_ADD_4(R,X,Y) \
- __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \
- X##_f[3], X##_f[2], X##_f[1], X##_f[0], \
- Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_SUB_4(R,X,Y) \
- __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \
- X##_f[3], X##_f[2], X##_f[1], X##_f[0], \
- Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
-
-#define _FP_FRAC_ADDI_4(X,I) \
- __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
-
-#define _FP_ZEROFRAC_4 0,0,0,0
-#define _FP_MINFRAC_4 0,0,0,1
-
-#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
-#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0)
-#define _FP_FRAC_OVERP_4(fs,X) (X##_f[0] & _FP_OVERFLOW_##fs)
-
-#define _FP_FRAC_EQ_4(X,Y) \
- (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \
- && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
-
-#define _FP_FRAC_GT_4(X,Y) \
- (X##_f[3] > Y##_f[3] || \
- (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \
- (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \
- (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \
- )) \
- )) \
- )
-
-#define _FP_FRAC_GE_4(X,Y) \
- (X##_f[3] > Y##_f[3] || \
- (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \
- (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \
- (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \
- )) \
- )) \
- )
-
-
-#define _FP_FRAC_CLZ_4(R,X) \
- do { \
- if (X##_f[3]) \
- { \
- __FP_CLZ(R,X##_f[3]); \
- } \
- else if (X##_f[2]) \
- { \
- __FP_CLZ(R,X##_f[2]); \
- R += _FP_W_TYPE_SIZE; \
- } \
- else if (X##_f[1]) \
- { \
- __FP_CLZ(R,X##_f[2]); \
- R += _FP_W_TYPE_SIZE*2; \
- } \
- else \
- { \
- __FP_CLZ(R,X##_f[0]); \
- R += _FP_W_TYPE_SIZE*3; \
- } \
- } while(0)
-
-
-#define _FP_UNPACK_RAW_4(fs, X, val) \
- do { \
- union _FP_UNION_##fs _flo; _flo.flt = (val); \
- X##_f[0] = _flo.bits.frac0; \
- X##_f[1] = _flo.bits.frac1; \
- X##_f[2] = _flo.bits.frac2; \
- X##_f[3] = _flo.bits.frac3; \
- X##_e = _flo.bits.exp; \
- X##_s = _flo.bits.sign; \
- } while (0)
-
-#define _FP_PACK_RAW_4(fs, val, X) \
- do { \
- union _FP_UNION_##fs _flo; \
- _flo.bits.frac0 = X##_f[0]; \
- _flo.bits.frac1 = X##_f[1]; \
- _flo.bits.frac2 = X##_f[2]; \
- _flo.bits.frac3 = X##_f[3]; \
- _flo.bits.exp = X##_e; \
- _flo.bits.sign = X##_s; \
- (val) = _flo.flt; \
- } while (0)
-
-
-/*
- * Internals
- */
-
-#define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \
- (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
-
-#ifndef __FP_FRAC_ADD_4
-#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
- do { \
- int _c1, _c2, _c3; \
- r0 = x0 + y0; \
- _c1 = r0 < x0; \
- r1 = x1 + y1; \
- _c2 = r1 < x1; \
- r1 += _c1; \
- _c2 |= r1 < _c1; \
- r2 = x2 + y2; \
- _c3 = r2 < x2; \
- r2 += _c2; \
- _c3 |= r2 < _c2; \
- r3 = x3 + y3 + _c3; \
- } while (0)
-#endif
-
-#ifndef __FP_FRAC_SUB_4
-#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
- do { \
- int _c1, _c2, _c3; \
- r0 = x0 - y0; \
- _c1 = r0 > x0; \
- r1 = x1 - y1; \
- _c2 = r1 > x1; \
- r1 -= _c1; \
- _c2 |= r1 > _c1; \
- r2 = x2 - y2; \
- _c3 = r2 > x2; \
- r2 -= _c2; \
- _c3 |= r2 > _c2; \
- r3 = x3 - y3 - _c3; \
- } while (0)
-#endif
-
-#ifndef __FP_FRAC_ADDI_4
-/* I always wanted to be a lisp programmer :-> */
-#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \
- (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
-#endif
-
-/* Convert FP values between word sizes. This appears to be more
- * complicated than I'd have expected it to be, so these might be
- * wrong... These macros are in any case somewhat bogus because they
- * use information about what various FRAC_n variables look like
- * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
- * the ones in op-2.h and op-1.h.
- */
-#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \
- do { \
- _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
- _FP_WFRACBITS_##sfs); \
- D##_f = S##_f[0]; \
- } while (0)
-
-#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \
- do { \
- _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
- _FP_WFRACBITS_##sfs); \
- D##_f0 = S##_f[0]; \
- D##_f1 = S##_f[1]; \
- } while (0)
-
-/* Assembly/disassembly for converting to/from integral types.
- * No shifting or overflow handled here.
- */
-/* Put the FP value X into r, which is an integer of size rsize. */
-#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \
- do { \
- if (rsize <= _FP_W_TYPE_SIZE) \
- r = X##_f[0]; \
- else if (rsize <= 2*_FP_W_TYPE_SIZE) \
- { \
- r = X##_f[1]; \
- r <<= _FP_W_TYPE_SIZE; \
- r += X##_f[0]; \
- } \
- else \
- { \
- /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
- /* and int == 4words as a single case. */ \
- r = X##_f[3]; \
- r <<= _FP_W_TYPE_SIZE; \
- r += X##_f[2]; \
- r <<= _FP_W_TYPE_SIZE; \
- r += X##_f[1]; \
- r <<= _FP_W_TYPE_SIZE; \
- r += X##_f[0]; \
- } \
- } while (0)
-
-/* "No disassemble Number Five!" */
-/* move an integer of size rsize into X's fractional part. We rely on
- * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
- * having to mask the values we store into it.
- */
-#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \
- do { \
- X##_f[0] = r; \
- X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \
- X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
- X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
- } while (0)
-
-#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \
- do { \
- D##_f[0] = S##_f; \
- D##_f[1] = D##_f[2] = D##_f[3] = 0; \
- _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
- } while (0)
-
-#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \
- do { \
- D##_f[0] = S##_f0; \
- D##_f[1] = S##_f1; \
- D##_f[2] = D##_f[3] = 0; \
- _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
- } while (0)
-
-/* FIXME! This has to be written */
-#define _FP_SQRT_MEAT_4(R, S, T, X, q)
diff --git a/arch/powerpc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h
deleted file mode 100644
index afb82b6498c..00000000000
--- a/arch/powerpc/math-emu/op-common.h
+++ /dev/null
@@ -1,688 +0,0 @@
-#define _FP_DECL(wc, X) \
- _FP_I_TYPE X##_c, X##_s, X##_e; \
- _FP_FRAC_DECL_##wc(X)
-
-/*
- * Finish truely unpacking a native fp value by classifying the kind
- * of fp value and normalizing both the exponent and the fraction.
- */
-
-#define _FP_UNPACK_CANONICAL(fs, wc, X) \
-do { \
- switch (X##_e) \
- { \
- default: \
- _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs; \
- _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \
- X##_e -= _FP_EXPBIAS_##fs; \
- X##_c = FP_CLS_NORMAL; \
- break; \
- \
- case 0: \
- if (_FP_FRAC_ZEROP_##wc(X)) \
- X##_c = FP_CLS_ZERO; \
- else \
- { \
- /* a denormalized number */ \
- _FP_I_TYPE _shift; \
- _FP_FRAC_CLZ_##wc(_shift, X); \
- _shift -= _FP_FRACXBITS_##fs; \
- _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \
- X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \
- X##_c = FP_CLS_NORMAL; \
- } \
- break; \
- \
- case _FP_EXPMAX_##fs: \
- if (_FP_FRAC_ZEROP_##wc(X)) \
- X##_c = FP_CLS_INF; \
- else \
- /* we don't differentiate between signaling and quiet nans */ \
- X##_c = FP_CLS_NAN; \
- break; \
- } \
-} while (0)
-
-
-/*
- * Before packing the bits back into the native fp result, take care
- * of such mundane things as rounding and overflow. Also, for some
- * kinds of fp values, the original parts may not have been fully
- * extracted -- but that is ok, we can regenerate them now.
- */
-
-#define _FP_PACK_CANONICAL(fs, wc, X) \
-({int __ret = 0; \
- switch (X##_c) \
- { \
- case FP_CLS_NORMAL: \
- X##_e += _FP_EXPBIAS_##fs; \
- if (X##_e > 0) \
- { \
- __ret |= _FP_ROUND(wc, X); \
- if (_FP_FRAC_OVERP_##wc(fs, X)) \
- { \
- _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \
- X##_e++; \
- } \
- else \
- _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
- if (X##_e >= _FP_EXPMAX_##fs) \
- { \
- /* overflow to infinity */ \
- X##_e = _FP_EXPMAX_##fs; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- __ret |= EFLAG_OVERFLOW; \
- } \
- } \
- else \
- { \
- /* we've got a denormalized number */ \
- X##_e = -X##_e + 1; \
- if (X##_e <= _FP_WFRACBITS_##fs) \
- { \
- _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
- _FP_FRAC_SLL_##wc(X, 1); \
- if (_FP_FRAC_OVERP_##wc(fs, X)) \
- { \
- X##_e = 1; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- } \
- else \
- { \
- X##_e = 0; \
- _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \
- __ret |= EFLAG_UNDERFLOW; \
- } \
- } \
- else \
- { \
- /* underflow to zero */ \
- X##_e = 0; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- __ret |= EFLAG_UNDERFLOW; \
- } \
- } \
- break; \
- \
- case FP_CLS_ZERO: \
- X##_e = 0; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- break; \
- \
- case FP_CLS_INF: \
- X##_e = _FP_EXPMAX_##fs; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- break; \
- \
- case FP_CLS_NAN: \
- X##_e = _FP_EXPMAX_##fs; \
- if (!_FP_KEEPNANFRACP) \
- { \
- _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \
- X##_s = 0; \
- } \
- else \
- _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \
- break; \
- } \
- __ret; \
-})
-
-
-/*
- * Main addition routine. The input values should be cooked.
- */
-
-#define _FP_ADD(fs, wc, R, X, Y) \
-do { \
- switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
- { \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
- { \
- /* shift the smaller number so that its exponent matches the larger */ \
- _FP_I_TYPE diff = X##_e - Y##_e; \
- \
- if (diff < 0) \
- { \
- diff = -diff; \
- if (diff <= _FP_WFRACBITS_##fs) \
- _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \
- else if (!_FP_FRAC_ZEROP_##wc(X)) \
- _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \
- else \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- R##_e = Y##_e; \
- } \
- else \
- { \
- if (diff > 0) \
- { \
- if (diff <= _FP_WFRACBITS_##fs) \
- _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \
- else if (!_FP_FRAC_ZEROP_##wc(Y)) \
- _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \
- else \
- _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \
- } \
- R##_e = X##_e; \
- } \
- \
- R##_c = FP_CLS_NORMAL; \
- \
- if (X##_s == Y##_s) \
- { \
- R##_s = X##_s; \
- _FP_FRAC_ADD_##wc(R, X, Y); \
- if (_FP_FRAC_OVERP_##wc(fs, R)) \
- { \
- _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \
- R##_e++; \
- } \
- } \
- else \
- { \
- R##_s = X##_s; \
- _FP_FRAC_SUB_##wc(R, X, Y); \
- if (_FP_FRAC_ZEROP_##wc(R)) \
- { \
- /* return an exact zero */ \
- if (FP_ROUNDMODE == FP_RND_MINF) \
- R##_s |= Y##_s; \
- else \
- R##_s &= Y##_s; \
- R##_c = FP_CLS_ZERO; \
- } \
- else \
- { \
- if (_FP_FRAC_NEGP_##wc(R)) \
- { \
- _FP_FRAC_SUB_##wc(R, Y, X); \
- R##_s = Y##_s; \
- } \
- \
- /* renormalize after subtraction */ \
- _FP_FRAC_CLZ_##wc(diff, R); \
- diff -= _FP_WFRACXBITS_##fs; \
- if (diff) \
- { \
- R##_e -= diff; \
- _FP_FRAC_SLL_##wc(R, diff); \
- } \
- } \
- } \
- break; \
- } \
- \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
- _FP_CHOOSENAN(fs, wc, R, X, Y); \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
- R##_e = X##_e; \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
- _FP_FRAC_COPY_##wc(R, X); \
- R##_s = X##_s; \
- R##_c = X##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
- R##_e = Y##_e; \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
- _FP_FRAC_COPY_##wc(R, Y); \
- R##_s = Y##_s; \
- R##_c = Y##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
- if (X##_s != Y##_s) \
- { \
- /* +INF + -INF => NAN */ \
- _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
- R##_s = X##_s ^ Y##_s; \
- R##_c = FP_CLS_NAN; \
- break; \
- } \
- /* FALLTHRU */ \
- \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
- R##_s = X##_s; \
- R##_c = FP_CLS_INF; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
- R##_s = Y##_s; \
- R##_c = FP_CLS_INF; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
- /* make sure the sign is correct */ \
- if (FP_ROUNDMODE == FP_RND_MINF) \
- R##_s = X##_s | Y##_s; \
- else \
- R##_s = X##_s & Y##_s; \
- R##_c = FP_CLS_ZERO; \
- break; \
- \
- default: \
- abort(); \
- } \
-} while (0)
-
-
-/*
- * Main negation routine. FIXME -- when we care about setting exception
- * bits reliably, this will not do. We should examine all of the fp classes.
- */
-
-#define _FP_NEG(fs, wc, R, X) \
- do { \
- _FP_FRAC_COPY_##wc(R, X); \
- R##_c = X##_c; \
- R##_e = X##_e; \
- R##_s = 1 ^ X##_s; \
- } while (0)
-
-
-/*
- * Main multiplication routine. The input values should be cooked.
- */
-
-#define _FP_MUL(fs, wc, R, X, Y) \
-do { \
- R##_s = X##_s ^ Y##_s; \
- switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
- { \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
- R##_c = FP_CLS_NORMAL; \
- R##_e = X##_e + Y##_e + 1; \
- \
- _FP_MUL_MEAT_##fs(R,X,Y); \
- \
- if (_FP_FRAC_OVERP_##wc(fs, R)) \
- _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \
- else \
- R##_e--; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
- _FP_CHOOSENAN(fs, wc, R, X, Y); \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
- R##_s = X##_s; \
- \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
- _FP_FRAC_COPY_##wc(R, X); \
- R##_c = X##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
- R##_s = Y##_s; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
- _FP_FRAC_COPY_##wc(R, Y); \
- R##_c = Y##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
- R##_c = FP_CLS_NAN; \
- _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
- break; \
- \
- default: \
- abort(); \
- } \
-} while (0)
-
-
-/*
- * Main division routine. The input values should be cooked.
- */
-
-#define _FP_DIV(fs, wc, R, X, Y) \
-do { \
- R##_s = X##_s ^ Y##_s; \
- switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
- { \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
- R##_c = FP_CLS_NORMAL; \
- R##_e = X##_e - Y##_e; \
- \
- _FP_DIV_MEAT_##fs(R,X,Y); \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
- _FP_CHOOSENAN(fs, wc, R, X, Y); \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
- R##_s = X##_s; \
- _FP_FRAC_COPY_##wc(R, X); \
- R##_c = X##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
- R##_s = Y##_s; \
- _FP_FRAC_COPY_##wc(R, Y); \
- R##_c = Y##_c; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
- R##_c = FP_CLS_ZERO; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
- R##_c = FP_CLS_INF; \
- break; \
- \
- case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
- case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
- R##_c = FP_CLS_NAN; \
- _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
- break; \
- \
- default: \
- abort(); \
- } \
-} while (0)
-
-
-/*
- * Main differential comparison routine. The inputs should be raw not
- * cooked. The return is -1,0,1 for normal values, 2 otherwise.
- */
-
-#define _FP_CMP(fs, wc, ret, X, Y, un) \
- do { \
- /* NANs are unordered */ \
- if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \
- || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \
- { \
- ret = un; \
- } \
- else \
- { \
- int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \
- int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \
- \
- if (__x_zero && __y_zero) \
- ret = 0; \
- else if (__x_zero) \
- ret = Y##_s ? 1 : -1; \
- else if (__y_zero) \
- ret = X##_s ? -1 : 1; \
- else if (X##_s != Y##_s) \
- ret = X##_s ? -1 : 1; \
- else if (X##_e > Y##_e) \
- ret = X##_s ? -1 : 1; \
- else if (X##_e < Y##_e) \
- ret = X##_s ? 1 : -1; \
- else if (_FP_FRAC_GT_##wc(X, Y)) \
- ret = X##_s ? -1 : 1; \
- else if (_FP_FRAC_GT_##wc(Y, X)) \
- ret = X##_s ? 1 : -1; \
- else \
- ret = 0; \
- } \
- } while (0)
-
-
-/* Simplification for strict equality. */
-
-#define _FP_CMP_EQ(fs, wc, ret, X, Y) \
- do { \
- /* NANs are unordered */ \
- if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \
- || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \
- { \
- ret = 1; \
- } \
- else \
- { \
- ret = !(X##_e == Y##_e \
- && _FP_FRAC_EQ_##wc(X, Y) \
- && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
- } \
- } while (0)
-
-/*
- * Main square root routine. The input value should be cooked.
- */
-
-#define _FP_SQRT(fs, wc, R, X) \
-do { \
- _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \
- _FP_W_TYPE q; \
- switch (X##_c) \
- { \
- case FP_CLS_NAN: \
- R##_s = 0; \
- R##_c = FP_CLS_NAN; \
- _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
- break; \
- case FP_CLS_INF: \
- if (X##_s) \
- { \
- R##_s = 0; \
- R##_c = FP_CLS_NAN; /* sNAN */ \
- } \
- else \
- { \
- R##_s = 0; \
- R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \
- } \
- break; \
- case FP_CLS_ZERO: \
- R##_s = X##_s; \
- R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \
- break; \
- case FP_CLS_NORMAL: \
- R##_s = 0; \
- if (X##_s) \
- { \
- R##_c = FP_CLS_NAN; /* sNAN */ \
- break; \
- } \
- R##_c = FP_CLS_NORMAL; \
- if (X##_e & 1) \
- _FP_FRAC_SLL_##wc(X, 1); \
- R##_e = X##_e >> 1; \
- _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \
- _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \
- q = _FP_OVERFLOW_##fs; \
- _FP_FRAC_SLL_##wc(X, 1); \
- _FP_SQRT_MEAT_##wc(R, S, T, X, q); \
- _FP_FRAC_SRL_##wc(R, 1); \
- } \
- } while (0)
-
-/*
- * Convert from FP to integer
- */
-
-/* "When a NaN, infinity, large positive argument >= 2147483648.0, or
- * large negative argument <= -2147483649.0 is converted to an integer,
- * the invalid_current bit...should be set and fp_exception_IEEE_754 should
- * be raised. If the floating point invalid trap is disabled, no trap occurs
- * and a numerical result is generated: if the sign bit of the operand
- * is 0, the result is 2147483647; if the sign bit of the operand is 1,
- * the result is -2147483648."
- * Similarly for conversion to extended ints, except that the boundaries
- * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
- * -2^63 for s=1.
- * -- SPARC Architecture Manual V9, Appendix B, which specifies how
- * SPARCs resolve implementation dependencies in the IEEE-754 spec.
- * I don't believe that the code below follows this. I'm not even sure
- * it's right!
- * It doesn't cope with needing to convert to an n bit integer when there
- * is no n bit integer type. Fortunately gcc provides long long so this
- * isn't a problem for sparc32.
- * I have, however, fixed its NaN handling to conform as above.
- * -- PMM 02/1998
- * NB: rsigned is not 'is r declared signed?' but 'should the value stored
- * in r be signed or unsigned?'. r is always(?) declared unsigned.
- * Comments below are mine, BTW -- PMM
- */
-#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \
- do { \
- switch (X##_c) \
- { \
- case FP_CLS_NORMAL: \
- if (X##_e < 0) \
- { \
- /* case FP_CLS_NAN: see above! */ \
- case FP_CLS_ZERO: \
- r = 0; \
- } \
- else if (X##_e >= rsize - (rsigned != 0)) \
- { /* overflow */ \
- case FP_CLS_NAN: \
- case FP_CLS_INF: \
- if (rsigned) \
- { \
- r = 1; \
- r <<= rsize - 1; \
- r -= 1 - X##_s; \
- } \
- else \
- { \
- r = 0; \
- if (!X##_s) \
- r = ~r; \
- } \
- } \
- else \
- { \
- if (_FP_W_TYPE_SIZE*wc < rsize) \
- { \
- _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
- r <<= X##_e - _FP_WFRACBITS_##fs; \
- } \
- else \
- { \
- if (X##_e >= _FP_WFRACBITS_##fs) \
- _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));\
- else \
- _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));\
- _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
- } \
- if (rsigned && X##_s) \
- r = -r; \
- } \
- break; \
- } \
- } while (0)
-
-#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \
- do { \
- if (r) \
- { \
- X##_c = FP_CLS_NORMAL; \
- \
- if ((X##_s = (r < 0))) \
- r = -r; \
- /* Note that `r' is now considered unsigned, so we don't have \
- to worry about the single signed overflow case. */ \
- \
- if (rsize <= _FP_W_TYPE_SIZE) \
- __FP_CLZ(X##_e, r); \
- else \
- __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \
- (_FP_W_TYPE)r); \
- if (rsize < _FP_W_TYPE_SIZE) \
- X##_e -= (_FP_W_TYPE_SIZE - rsize); \
- X##_e = rsize - X##_e - 1; \
- \
- if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \
- __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \
- r &= ~((_FP_W_TYPE)1 << X##_e); \
- _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \
- _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \
- } \
- else \
- { \
- X##_c = FP_CLS_ZERO, X##_s = 0; \
- } \
- } while (0)
-
-
-#define FP_CONV(dfs,sfs,dwc,swc,D,S) \
- do { \
- _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \
- D##_e = S##_e; \
- D##_c = S##_c; \
- D##_s = S##_s; \
- } while (0)
-
-/*
- * Helper primitives.
- */
-
-/* Count leading zeros in a word. */
-
-#ifndef __FP_CLZ
-#if _FP_W_TYPE_SIZE < 64
-/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
-#define __FP_CLZ(r, x) \
- do { \
- _FP_W_TYPE _t = (x); \
- r = _FP_W_TYPE_SIZE - 1; \
- if (_t > 0xffff) r -= 16; \
- if (_t > 0xffff) _t >>= 16; \
- if (_t > 0xff) r -= 8; \
- if (_t > 0xff) _t >>= 8; \
- if (_t & 0xf0) r -= 4; \
- if (_t & 0xf0) _t >>= 4; \
- if (_t & 0xc) r -= 2; \
- if (_t & 0xc) _t >>= 2; \
- if (_t & 0x2) r -= 1; \
- } while (0)
-#else /* not _FP_W_TYPE_SIZE < 64 */
-#define __FP_CLZ(r, x) \
- do { \
- _FP_W_TYPE _t = (x); \
- r = _FP_W_TYPE_SIZE - 1; \
- if (_t > 0xffffffff) r -= 32; \
- if (_t > 0xffffffff) _t >>= 32; \
- if (_t > 0xffff) r -= 16; \
- if (_t > 0xffff) _t >>= 16; \
- if (_t > 0xff) r -= 8; \
- if (_t > 0xff) _t >>= 8; \
- if (_t & 0xf0) r -= 4; \
- if (_t & 0xf0) _t >>= 4; \
- if (_t & 0xc) r -= 2; \
- if (_t & 0xc) _t >>= 2; \
- if (_t & 0x2) r -= 1; \
- } while (0)
-#endif /* not _FP_W_TYPE_SIZE < 64 */
-#endif /* ndef __FP_CLZ */
-
-#define _FP_DIV_HELP_imm(q, r, n, d) \
- do { \
- q = n / d, r = n % d; \
- } while (0)
-
diff --git a/arch/powerpc/math-emu/single.h b/arch/powerpc/math-emu/single.h
deleted file mode 100644
index f19d9945181..00000000000
--- a/arch/powerpc/math-emu/single.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Definitions for IEEE Single Precision
- */
-
-#if _FP_W_TYPE_SIZE < 32
-#error "Here's a nickel kid. Go buy yourself a real computer."
-#endif
-
-#define _FP_FRACBITS_S 24
-#define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S)
-#define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S)
-#define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S)
-#define _FP_EXPBITS_S 8
-#define _FP_EXPBIAS_S 127
-#define _FP_EXPMAX_S 255
-#define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2))
-#define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1))
-#define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S))
-
-/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be
- chosen by the target machine. */
-
-union _FP_UNION_S
-{
- float flt;
- struct {
-#if __BYTE_ORDER == __BIG_ENDIAN
- unsigned sign : 1;
- unsigned exp : _FP_EXPBITS_S;
- unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
-#else
- unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
- unsigned exp : _FP_EXPBITS_S;
- unsigned sign : 1;
-#endif
- } bits __attribute__((packed));
-};
-
-#define FP_DECL_S(X) _FP_DECL(1,X)
-#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val)
-#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X)
-
-#define FP_UNPACK_S(X,val) \
- do { \
- _FP_UNPACK_RAW_1(S,X,val); \
- _FP_UNPACK_CANONICAL(S,1,X); \
- } while (0)
-
-#define FP_PACK_S(val,X) \
- do { \
- _FP_PACK_CANONICAL(S,1,X); \
- _FP_PACK_RAW_1(S,val,X); \
- } while (0)
-
-#define FP_NEG_S(R,X) _FP_NEG(S,1,R,X)
-#define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y)
-#define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y)
-#define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y)
-#define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y)
-#define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X)
-
-#define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un)
-#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y)
-
-#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg)
-#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt)
diff --git a/arch/powerpc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h
deleted file mode 100644
index cca39598f87..00000000000
--- a/arch/powerpc/math-emu/soft-fp.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef SOFT_FP_H
-#define SOFT_FP_H
-
-#include "sfp-machine.h"
-
-#define _FP_WORKBITS 3
-#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3)
-#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2)
-#define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1)
-#define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0)
-
-#ifndef FP_RND_NEAREST
-# define FP_RND_NEAREST 0
-# define FP_RND_ZERO 1
-# define FP_RND_PINF 2
-# define FP_RND_MINF 3
-#ifndef FP_ROUNDMODE
-# define FP_ROUNDMODE FP_RND_NEAREST
-#endif
-#endif
-
-#define _FP_ROUND_NEAREST(wc, X) \
-({ int __ret = 0; \
- int __frac = _FP_FRAC_LOW_##wc(X) & 15; \
- if (__frac & 7) { \
- __ret = EFLAG_INEXACT; \
- if ((__frac & 7) != _FP_WORK_ROUND) \
- _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \
- else if (__frac & _FP_WORK_LSB) \
- _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \
- } \
- __ret; \
-})
-
-#define _FP_ROUND_ZERO(wc, X) \
-({ int __ret = 0; \
- if (_FP_FRAC_LOW_##wc(X) & 7) \
- __ret = EFLAG_INEXACT; \
- __ret; \
-})
-
-#define _FP_ROUND_PINF(wc, X) \
-({ int __ret = EFLAG_INEXACT; \
- if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
- _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
- else __ret = 0; \
- __ret; \
-})
-
-#define _FP_ROUND_MINF(wc, X) \
-({ int __ret = EFLAG_INEXACT; \
- if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
- _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
- else __ret = 0; \
- __ret; \
-})
-
-#define _FP_ROUND(wc, X) \
-({ int __ret = 0; \
- switch (FP_ROUNDMODE) \
- { \
- case FP_RND_NEAREST: \
- __ret |= _FP_ROUND_NEAREST(wc,X); \
- break; \
- case FP_RND_ZERO: \
- __ret |= _FP_ROUND_ZERO(wc,X); \
- break; \
- case FP_RND_PINF: \
- __ret |= _FP_ROUND_PINF(wc,X); \
- break; \
- case FP_RND_MINF: \
- __ret |= _FP_ROUND_MINF(wc,X); \
- break; \
- }; \
- __ret; \
-})
-
-#define FP_CLS_NORMAL 0
-#define FP_CLS_ZERO 1
-#define FP_CLS_INF 2
-#define FP_CLS_NAN 3
-
-#define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y))
-
-#include "op-1.h"
-#include "op-2.h"
-#include "op-4.h"
-#include "op-common.h"
-
-/* Sigh. Silly things longlong.h needs. */
-#define UWtype _FP_W_TYPE
-#define W_TYPE_SIZE _FP_W_TYPE_SIZE
-
-typedef int SItype __attribute__((mode(SI)));
-typedef int DItype __attribute__((mode(DI)));
-typedef unsigned int USItype __attribute__((mode(SI)));
-typedef unsigned int UDItype __attribute__((mode(DI)));
-#if _FP_W_TYPE_SIZE == 32
-typedef unsigned int UHWtype __attribute__((mode(HI)));
-#elif _FP_W_TYPE_SIZE == 64
-typedef USItype UHWtype;
-#endif
-
-#endif
diff --git a/arch/powerpc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c
index 8689aa48ef6..6122147356d 100644
--- a/arch/powerpc/math-emu/stfs.c
+++ b/arch/powerpc/math-emu/stfs.c
@@ -2,23 +2,24 @@
#include <linux/errno.h>
#include <asm/uaccess.h>
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
+#include <asm/sfp-machine.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/double.h>
+#include <math-emu/single.h>
int
stfs(void *frS, void *ea)
{
FP_DECL_D(A);
FP_DECL_S(R);
+ FP_DECL_EX;
float f;
- int err;
#ifdef DEBUG
printk("%s: S %p, ea %p\n", __func__, frS, ea);
#endif
- __FP_UNPACK_D(A, frS);
+ FP_UNPACK_DP(A, frS);
#ifdef DEBUG
printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
@@ -30,12 +31,12 @@ stfs(void *frS, void *ea)
printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c);
#endif
- err = _FP_PACK_CANONICAL(S, 1, R);
- if (!err || !__FPU_TRAP_P(err)) {
- __FP_PACK_RAW_1(S, &f, R);
+ _FP_PACK_CANONICAL(S, 1, R);
+ if (!FP_CUR_EXCEPTIONS || !__FPU_TRAP_P(FP_CUR_EXCEPTIONS)) {
+ _FP_PACK_RAW_1_P(S, &f, R);
if (copy_to_user(ea, &f, sizeof(float)))
return -EFAULT;
}
- return err;
+ return FP_CUR_EXCEPTIONS;
}
diff --git a/arch/powerpc/math-emu/types.c b/arch/powerpc/math-emu/types.c
deleted file mode 100644
index e1ed15d829d..00000000000
--- a/arch/powerpc/math-emu/types.c
+++ /dev/null
@@ -1,51 +0,0 @@
-#include "soft-fp.h"
-#include "double.h"
-#include "single.h"
-
-void
-fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0,
- long *_e, long *_c, void *val)
-{
- FP_DECL_D(X);
-
- __FP_UNPACK_RAW_2(D, X, val);
-
- _FP_UNPACK_CANONICAL(D, 2, X);
-
- *_s = X_s;
- *_f1 = X_f1;
- *_f0 = X_f0;
- *_e = X_e;
- *_c = X_c;
-}
-
-int
-fp_pack_d(void *val, long X_s, unsigned long X_f1,
- unsigned long X_f0, long X_e, long X_c)
-{
- int exc;
-
- exc = _FP_PACK_CANONICAL(D, 2, X);
- if (!exc || !__FPU_TRAP_P(exc))
- __FP_PACK_RAW_2(D, val, X);
- return exc;
-}
-
-int
-fp_pack_ds(void *val, long X_s, unsigned long X_f1,
- unsigned long X_f0, long X_e, long X_c)
-{
- FP_DECL_S(__X);
- int exc;
-
- FP_CONV(S, D, 1, 2, __X, X);
- exc = _FP_PACK_CANONICAL(S, 1, __X);
- if (!exc || !__FPU_TRAP_P(exc)) {
- _FP_UNPACK_CANONICAL(S, 1, __X);
- FP_CONV(D, S, 2, 1, X, __X);
- exc |= _FP_PACK_CANONICAL(D, 2, X);
- if (!exc || !__FPU_TRAP_P(exc))
- __FP_PACK_RAW_2(D, val, X);
- }
- return exc;
-}
diff --git a/arch/powerpc/math-emu/udivmodti4.c b/arch/powerpc/math-emu/udivmodti4.c
index 7e112dc1e2f..6172044ab00 100644
--- a/arch/powerpc/math-emu/udivmodti4.c
+++ b/arch/powerpc/math-emu/udivmodti4.c
@@ -1,6 +1,6 @@
/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */
-#include "soft-fp.h"
+#include <math-emu/soft-fp.h>
#undef count_leading_zeros
#define count_leading_zeros __FP_CLZ
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c
index ce10e2b1b90..23cee39534f 100644
--- a/arch/powerpc/mm/fsl_booke_mmu.c
+++ b/arch/powerpc/mm/fsl_booke_mmu.c
@@ -202,7 +202,7 @@ adjust_total_lowmem(void)
cam_max_size = max_lowmem_size;
/* adjust lowmem size to max_lowmem_size */
- ram = min(max_lowmem_size, (phys_addr_t)total_lowmem);
+ ram = min(max_lowmem_size, total_lowmem);
/* Calculate CAM values */
__cam0 = 1UL << 2 * (__ilog2(ram) / 2);
@@ -225,7 +225,8 @@ adjust_total_lowmem(void)
printk(KERN_INFO "Memory CAM mapping: CAM0=%ldMb, CAM1=%ldMb,"
" CAM2=%ldMb residual: %ldMb\n",
__cam0 >> 20, __cam1 >> 20, __cam2 >> 20,
- (total_lowmem - __cam0 - __cam1 - __cam2) >> 20);
+ (long int)((total_lowmem - __cam0 - __cam1 - __cam2)
+ >> 20));
__max_low_memory = __cam0 + __cam1 + __cam2;
__initial_memory_limit_addr = memstart_addr + __max_low_memory;
}
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index 9fdf4d6335e..28a114db3ba 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -41,7 +41,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
page = pte_page(pte);
if (!page_cache_get_speculative(page))
return 0;
- if (unlikely(pte != *ptep)) {
+ if (unlikely(pte_val(pte) != pte_val(*ptep))) {
put_page(page);
return 0;
}
@@ -92,7 +92,7 @@ static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate,
*nr -= refs;
return 0;
}
- if (unlikely(pte != *ptep)) {
+ if (unlikely(pte_val(pte) != pte_val(*ptep))) {
/* Could be optimized better */
while (*nr) {
put_page(page);
@@ -237,7 +237,8 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
pgd_t pgd = *pgdp;
VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift);
- pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd);
+ pr_debug(" %016lx: normal pgd %p\n", addr,
+ (void *)pgd_val(pgd));
next = pgd_addr_end(addr, end);
if (pgd_none(pgd))
goto slow;
diff --git a/arch/powerpc/mm/hash_low_32.S b/arch/powerpc/mm/hash_low_32.S
index b9ba7d93080..7bffb70b9fe 100644
--- a/arch/powerpc/mm/hash_low_32.S
+++ b/arch/powerpc/mm/hash_low_32.S
@@ -75,7 +75,7 @@ _GLOBAL(hash_page_sync)
* Returns to the caller if the access is illegal or there is no
* mapping for the address. Otherwise it places an appropriate PTE
* in the hash table and returns from the exception.
- * Uses r0, r3 - r8, ctr, lr.
+ * Uses r0, r3 - r8, r10, ctr, lr.
*/
.text
_GLOBAL(hash_page)
@@ -106,9 +106,15 @@ _GLOBAL(hash_page)
addi r5,r5,swapper_pg_dir@l /* kernel page table */
rlwimi r3,r9,32-12,29,29 /* MSR_PR -> _PAGE_USER */
112: add r5,r5,r7 /* convert to phys addr */
+#ifndef CONFIG_PTE_64BIT
rlwimi r5,r4,12,20,29 /* insert top 10 bits of address */
lwz r8,0(r5) /* get pmd entry */
rlwinm. r8,r8,0,0,19 /* extract address of pte page */
+#else
+ rlwinm r8,r4,13,19,29 /* Compute pgdir/pmd offset */
+ lwzx r8,r8,r5 /* Get L1 entry */
+ rlwinm. r8,r8,0,0,20 /* extract pt base address */
+#endif
#ifdef CONFIG_SMP
beq- hash_page_out /* return if no mapping */
#else
@@ -118,7 +124,11 @@ _GLOBAL(hash_page)
to the address following the rfi. */
beqlr-
#endif
+#ifndef CONFIG_PTE_64BIT
rlwimi r8,r4,22,20,29 /* insert next 10 bits of address */
+#else
+ rlwimi r8,r4,23,20,28 /* compute pte address */
+#endif
rlwinm r0,r3,32-3,24,24 /* _PAGE_RW access -> _PAGE_DIRTY */
ori r0,r0,_PAGE_ACCESSED|_PAGE_HASHPTE
@@ -127,9 +137,15 @@ _GLOBAL(hash_page)
* because almost always, there won't be a permission violation
* and there won't already be an HPTE, and thus we will have
* to update the PTE to set _PAGE_HASHPTE. -- paulus.
+ *
+ * If PTE_64BIT is set, the low word is the flags word; use that
+ * word for locking since it contains all the interesting bits.
*/
+#if (PTE_FLAGS_OFFSET != 0)
+ addi r8,r8,PTE_FLAGS_OFFSET
+#endif
retry:
- lwarx r6,0,r8 /* get linux-style pte */
+ lwarx r6,0,r8 /* get linux-style pte, flag word */
andc. r5,r3,r6 /* check access & ~permission */
#ifdef CONFIG_SMP
bne- hash_page_out /* return if access not permitted */
@@ -137,6 +153,15 @@ retry:
bnelr-
#endif
or r5,r0,r6 /* set accessed/dirty bits */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+ subf r10,r6,r8 /* create false data dependency */
+ subi r10,r10,PTE_FLAGS_OFFSET
+ lwzx r10,r6,r10 /* Get upper PTE word */
+#else
+ lwz r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
stwcx. r5,0,r8 /* attempt to update PTE */
bne- retry /* retry if someone got there first */
@@ -203,9 +228,9 @@ _GLOBAL(add_hash_page)
* we can't take a hash table miss (assuming the code is
* covered by a BAT). -- paulus
*/
- mfmsr r10
+ mfmsr r9
SYNC
- rlwinm r0,r10,0,17,15 /* clear bit 16 (MSR_EE) */
+ rlwinm r0,r9,0,17,15 /* clear bit 16 (MSR_EE) */
rlwinm r0,r0,0,28,26 /* clear MSR_DR */
mtmsr r0
SYNC_601
@@ -214,14 +239,14 @@ _GLOBAL(add_hash_page)
tophys(r7,0)
#ifdef CONFIG_SMP
- addis r9,r7,mmu_hash_lock@ha
- addi r9,r9,mmu_hash_lock@l
-10: lwarx r0,0,r9 /* take the mmu_hash_lock */
+ addis r6,r7,mmu_hash_lock@ha
+ addi r6,r6,mmu_hash_lock@l
+10: lwarx r0,0,r6 /* take the mmu_hash_lock */
cmpi 0,r0,0
bne- 11f
- stwcx. r8,0,r9
+ stwcx. r8,0,r6
beq+ 12f
-11: lwz r0,0(r9)
+11: lwz r0,0(r6)
cmpi 0,r0,0
beq 10b
b 11b
@@ -234,10 +259,24 @@ _GLOBAL(add_hash_page)
* HPTE, so we just unlock and return.
*/
mr r8,r5
+#ifndef CONFIG_PTE_64BIT
rlwimi r8,r4,22,20,29
+#else
+ rlwimi r8,r4,23,20,28
+ addi r8,r8,PTE_FLAGS_OFFSET
+#endif
1: lwarx r6,0,r8
andi. r0,r6,_PAGE_HASHPTE
bne 9f /* if HASHPTE already set, done */
+#ifdef CONFIG_PTE_64BIT
+#ifdef CONFIG_SMP
+ subf r10,r6,r8 /* create false data dependency */
+ subi r10,r10,PTE_FLAGS_OFFSET
+ lwzx r10,r6,r10 /* Get upper PTE word */
+#else
+ lwz r10,-PTE_FLAGS_OFFSET(r8)
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_PTE_64BIT */
ori r5,r6,_PAGE_HASHPTE
stwcx. r5,0,r8
bne- 1b
@@ -246,13 +285,15 @@ _GLOBAL(add_hash_page)
9:
#ifdef CONFIG_SMP
+ addis r6,r7,mmu_hash_lock@ha
+ addi r6,r6,mmu_hash_lock@l
eieio
li r0,0
- stw r0,0(r9) /* clear mmu_hash_lock */
+ stw r0,0(r6) /* clear mmu_hash_lock */
#endif
/* reenable interrupts and DR */
- mtmsr r10
+ mtmsr r9
SYNC_601
isync
@@ -267,7 +308,8 @@ _GLOBAL(add_hash_page)
* r5 contains the linux PTE, r6 contains the old value of the
* linux PTE (before setting _PAGE_HASHPTE) and r7 contains the
* offset to be added to addresses (0 if the MMU is on,
- * -KERNELBASE if it is off).
+ * -KERNELBASE if it is off). r10 contains the upper half of
+ * the PTE if CONFIG_PTE_64BIT.
* On SMP, the caller should have the mmu_hash_lock held.
* We assume that the caller has (or will) set the _PAGE_HASHPTE
* bit in the linux PTE in memory. The value passed in r6 should
@@ -285,7 +327,7 @@ Hash_bits = 12 /* e.g. 256kB hash table */
Hash_msk = (((1 << Hash_bits) - 1) * 64)
/* defines for the PTE format for 32-bit PPCs */
-#define PTE_SIZE 8
+#define HPTE_SIZE 8
#define PTEG_SIZE 64
#define LG_PTEG_SIZE 6
#define LDPTEu lwzu
@@ -313,6 +355,11 @@ _GLOBAL(create_hpte)
BEGIN_FTR_SECTION
ori r8,r8,_PAGE_COHERENT /* set M (coherence required) */
END_FTR_SECTION_IFSET(CPU_FTR_NEED_COHERENT)
+#ifdef CONFIG_PTE_64BIT
+ /* Put the XPN bits into the PTE */
+ rlwimi r8,r10,8,20,22
+ rlwimi r8,r10,2,29,29
+#endif
/* Construct the high word of the PPC-style PTE (r5) */
rlwinm r5,r3,7,1,24 /* put VSID in 0x7fffff80 bits */
@@ -342,8 +389,8 @@ _GLOBAL(hash_page_patch_A)
/* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
mtctr r0
- addi r4,r3,-PTE_SIZE
-1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */
+ addi r4,r3,-HPTE_SIZE
+1: LDPTEu r6,HPTE_SIZE(r4) /* get next PTE */
CMPPTE 0,r6,r5
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ found_slot
@@ -353,9 +400,9 @@ _GLOBAL(hash_page_patch_A)
_GLOBAL(hash_page_patch_B)
xoris r4,r3,Hash_msk>>16 /* compute secondary hash */
xori r4,r4,(-PTEG_SIZE & 0xffff)
- addi r4,r4,-PTE_SIZE
+ addi r4,r4,-HPTE_SIZE
mtctr r0
-2: LDPTEu r6,PTE_SIZE(r4)
+2: LDPTEu r6,HPTE_SIZE(r4)
CMPPTE 0,r6,r5
bdnzf 2,2b
beq+ found_slot
@@ -363,8 +410,8 @@ _GLOBAL(hash_page_patch_B)
/* Search the primary PTEG for an empty slot */
10: mtctr r0
- addi r4,r3,-PTE_SIZE /* search primary PTEG */
-1: LDPTEu r6,PTE_SIZE(r4) /* get next PTE */
+ addi r4,r3,-HPTE_SIZE /* search primary PTEG */
+1: LDPTEu r6,HPTE_SIZE(r4) /* get next PTE */
TST_V(r6) /* test valid bit */
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ found_empty
@@ -380,9 +427,9 @@ _GLOBAL(hash_page_patch_B)
_GLOBAL(hash_page_patch_C)
xoris r4,r3,Hash_msk>>16 /* compute secondary hash */
xori r4,r4,(-PTEG_SIZE & 0xffff)
- addi r4,r4,-PTE_SIZE
+ addi r4,r4,-HPTE_SIZE
mtctr r0
-2: LDPTEu r6,PTE_SIZE(r4)
+2: LDPTEu r6,HPTE_SIZE(r4)
TST_V(r6)
bdnzf 2,2b
beq+ found_empty
@@ -409,11 +456,11 @@ _GLOBAL(hash_page_patch_C)
1: addis r4,r7,next_slot@ha /* get next evict slot */
lwz r6,next_slot@l(r4)
- addi r6,r6,PTE_SIZE /* search for candidate */
- andi. r6,r6,7*PTE_SIZE
+ addi r6,r6,HPTE_SIZE /* search for candidate */
+ andi. r6,r6,7*HPTE_SIZE
stw r6,next_slot@l(r4)
add r4,r3,r6
- LDPTE r0,PTE_SIZE/2(r4) /* get PTE second word */
+ LDPTE r0,HPTE_SIZE/2(r4) /* get PTE second word */
clrrwi r0,r0,12
lis r6,etext@h
ori r6,r6,etext@l /* get etext */
@@ -426,7 +473,7 @@ _GLOBAL(hash_page_patch_C)
found_empty:
STPTE r5,0(r4)
found_slot:
- STPTE r8,PTE_SIZE/2(r4)
+ STPTE r8,HPTE_SIZE/2(r4)
#else /* CONFIG_SMP */
/*
@@ -452,7 +499,7 @@ found_slot:
STPTE r5,0(r4)
sync
TLBSYNC
- STPTE r8,PTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
+ STPTE r8,HPTE_SIZE/2(r4) /* put in correct RPN, WIMG, PP bits */
sync
SET_V(r5)
STPTE r5,0(r4) /* finally set V bit in PTE */
@@ -499,14 +546,18 @@ _GLOBAL(flush_hash_pages)
isync
/* First find a PTE in the range that has _PAGE_HASHPTE set */
+#ifndef CONFIG_PTE_64BIT
rlwimi r5,r4,22,20,29
-1: lwz r0,0(r5)
+#else
+ rlwimi r5,r4,23,20,28
+#endif
+1: lwz r0,PTE_FLAGS_OFFSET(r5)
cmpwi cr1,r6,1
andi. r0,r0,_PAGE_HASHPTE
bne 2f
ble cr1,19f
addi r4,r4,0x1000
- addi r5,r5,4
+ addi r5,r5,PTE_SIZE
addi r6,r6,-1
b 1b
@@ -545,7 +596,10 @@ _GLOBAL(flush_hash_pages)
* already clear, we're done (for this pte). If not,
* clear it (atomically) and proceed. -- paulus.
*/
-33: lwarx r8,0,r5 /* fetch the pte */
+#if (PTE_FLAGS_OFFSET != 0)
+ addi r5,r5,PTE_FLAGS_OFFSET
+#endif
+33: lwarx r8,0,r5 /* fetch the pte flags word */
andi. r0,r8,_PAGE_HASHPTE
beq 8f /* done if HASHPTE is already clear */
rlwinm r8,r8,0,31,29 /* clear HASHPTE bit */
@@ -562,8 +616,8 @@ _GLOBAL(flush_hash_patch_A)
/* Search the primary PTEG for a PTE whose 1st (d)word matches r5 */
li r0,8 /* PTEs/group */
mtctr r0
- addi r12,r8,-PTE_SIZE
-1: LDPTEu r0,PTE_SIZE(r12) /* get next PTE */
+ addi r12,r8,-HPTE_SIZE
+1: LDPTEu r0,HPTE_SIZE(r12) /* get next PTE */
CMPPTE 0,r0,r11
bdnzf 2,1b /* loop while ctr != 0 && !cr0.eq */
beq+ 3f
@@ -574,9 +628,9 @@ _GLOBAL(flush_hash_patch_A)
_GLOBAL(flush_hash_patch_B)
xoris r12,r8,Hash_msk>>16 /* compute secondary hash */
xori r12,r12,(-PTEG_SIZE & 0xffff)
- addi r12,r12,-PTE_SIZE
+ addi r12,r12,-HPTE_SIZE
mtctr r0
-2: LDPTEu r0,PTE_SIZE(r12)
+2: LDPTEu r0,HPTE_SIZE(r12)
CMPPTE 0,r0,r11
bdnzf 2,2b
xori r11,r11,PTE_H /* clear H again */
@@ -590,7 +644,7 @@ _GLOBAL(flush_hash_patch_B)
8: ble cr1,9f /* if all ptes checked */
81: addi r6,r6,-1
- addi r5,r5,4 /* advance to next pte */
+ addi r5,r5,PTE_SIZE
addi r4,r4,0x1000
lwz r0,0(r5) /* check next pte */
cmpwi cr1,r6,1
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 8920eea3452..5c64af17475 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -194,7 +194,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
unsigned long tprot = prot;
/* Make kernel text executable */
- if (in_kernel_text(vaddr))
+ if (overlaps_kernel_text(vaddr, vaddr + step))
tprot &= ~HPTE_R_N;
hash = hpt_hash(va, shift, ssize);
@@ -348,6 +348,7 @@ static int __init htab_dt_scan_page_sizes(unsigned long node,
return 0;
}
+#ifdef CONFIG_HUGETLB_PAGE
/* Scan for 16G memory blocks that have been set aside for huge pages
* and reserve those blocks for 16G huge pages.
*/
@@ -385,6 +386,7 @@ static int __init htab_dt_scan_hugepage_blocks(unsigned long node,
add_gpage(phys_addr, block_size, expected_pages);
return 0;
}
+#endif /* CONFIG_HUGETLB_PAGE */
static void __init htab_init_page_sizes(void)
{
@@ -539,7 +541,7 @@ static unsigned long __init htab_get_table_size(void)
void create_section_mapping(unsigned long start, unsigned long end)
{
BUG_ON(htab_bolt_mapping(start, end, __pa(start),
- PAGE_KERNEL, mmu_linear_psize,
+ pgprot_val(PAGE_KERNEL), mmu_linear_psize,
mmu_kernel_ssize));
}
@@ -647,7 +649,7 @@ void __init htab_initialize(void)
mtspr(SPRN_SDR1, _SDR1);
}
- prot = PAGE_KERNEL;
+ prot = pgprot_val(PAGE_KERNEL);
#ifdef CONFIG_DEBUG_PAGEALLOC
linear_map_hash_count = lmb_end_of_DRAM() >> PAGE_SHIFT;
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index f1c2d55b437..a117024ab8c 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -128,29 +128,37 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,
return 0;
}
-/* Base page size affects how we walk hugetlb page tables */
-#ifdef CONFIG_PPC_64K_PAGES
-#define hpmd_offset(pud, addr, h) pmd_offset(pud, addr)
-#define hpmd_alloc(mm, pud, addr, h) pmd_alloc(mm, pud, addr)
-#else
-static inline
-pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate)
+
+static pud_t *hpud_offset(pgd_t *pgd, unsigned long addr, struct hstate *hstate)
+{
+ if (huge_page_shift(hstate) < PUD_SHIFT)
+ return pud_offset(pgd, addr);
+ else
+ return (pud_t *) pgd;
+}
+static pud_t *hpud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long addr,
+ struct hstate *hstate)
{
- if (huge_page_shift(hstate) == PAGE_SHIFT_64K)
+ if (huge_page_shift(hstate) < PUD_SHIFT)
+ return pud_alloc(mm, pgd, addr);
+ else
+ return (pud_t *) pgd;
+}
+static pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate)
+{
+ if (huge_page_shift(hstate) < PMD_SHIFT)
return pmd_offset(pud, addr);
else
return (pmd_t *) pud;
}
-static inline
-pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr,
- struct hstate *hstate)
+static pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr,
+ struct hstate *hstate)
{
- if (huge_page_shift(hstate) == PAGE_SHIFT_64K)
+ if (huge_page_shift(hstate) < PMD_SHIFT)
return pmd_alloc(mm, pud, addr);
else
return (pmd_t *) pud;
}
-#endif
/* Build list of addresses of gigantic pages. This function is used in early
* boot before the buddy or bootmem allocator is setup.
@@ -204,7 +212,7 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
pg = pgd_offset(mm, addr);
if (!pgd_none(*pg)) {
- pu = pud_offset(pg, addr);
+ pu = hpud_offset(pg, addr, hstate);
if (!pud_none(*pu)) {
pm = hpmd_offset(pu, addr, hstate);
if (!pmd_none(*pm))
@@ -233,7 +241,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
addr &= hstate->mask;
pg = pgd_offset(mm, addr);
- pu = pud_alloc(mm, pg, addr);
+ pu = hpud_alloc(mm, pg, addr, hstate);
if (pu) {
pm = hpmd_alloc(mm, pu, addr, hstate);
@@ -316,13 +324,7 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
pud = pud_offset(pgd, addr);
do {
next = pud_addr_end(addr, end);
-#ifdef CONFIG_PPC_64K_PAGES
- if (pud_none_or_clear_bad(pud))
- continue;
- hugetlb_free_pmd_range(tlb, pud, addr, next, floor, ceiling,
- psize);
-#else
- if (shift == PAGE_SHIFT_64K) {
+ if (shift < PMD_SHIFT) {
if (pud_none_or_clear_bad(pud))
continue;
hugetlb_free_pmd_range(tlb, pud, addr, next, floor,
@@ -332,7 +334,6 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd,
continue;
free_hugepte_range(tlb, (hugepd_t *)pud, psize);
}
-#endif
} while (pud++, addr = next, addr != end);
start &= PGDIR_MASK;
@@ -422,9 +423,15 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb,
psize = get_slice_psize(tlb->mm, addr);
BUG_ON(!mmu_huge_psizes[psize]);
next = pgd_addr_end(addr, end);
- if (pgd_none_or_clear_bad(pgd))
- continue;
- hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
+ if (mmu_psize_to_shift(psize) < PUD_SHIFT) {
+ if (pgd_none_or_clear_bad(pgd))
+ continue;
+ hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling);
+ } else {
+ if (pgd_none(*pgd))
+ continue;
+ free_hugepte_range(tlb, (hugepd_t *)pgd, psize);
+ }
} while (pgd++, addr = next, addr != end);
}
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index 036fe2f10c7..3e6a6543f53 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -228,8 +228,8 @@ int __meminit vmemmap_populate(struct page *start_page,
start, p, __pa(p));
mapped = htab_bolt_mapping(start, start + page_size, __pa(p),
- PAGE_KERNEL, mmu_vmemmap_psize,
- mmu_kernel_ssize);
+ pgprot_val(PAGE_KERNEL),
+ mmu_vmemmap_psize, mmu_kernel_ssize);
BUG_ON(mapped < 0);
}
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 1c93c255873..98d7bf99533 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -75,11 +75,10 @@ static inline pte_t *virt_to_kpte(unsigned long vaddr)
int page_is_ram(unsigned long pfn)
{
- unsigned long paddr = (pfn << PAGE_SHIFT);
-
#ifndef CONFIG_PPC64 /* XXX for now */
- return paddr < __pa(high_memory);
+ return pfn < max_pfn;
#else
+ unsigned long paddr = (pfn << PAGE_SHIFT);
int i;
for (i=0; i < lmb.memory.cnt; i++) {
unsigned long base;
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index d9a18135133..6cf5c71c431 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -89,6 +89,46 @@ static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
return 0;
}
+/*
+ * get_active_region_work_fn - A helper function for get_node_active_region
+ * Returns datax set to the start_pfn and end_pfn if they contain
+ * the initial value of datax->start_pfn between them
+ * @start_pfn: start page(inclusive) of region to check
+ * @end_pfn: end page(exclusive) of region to check
+ * @datax: comes in with ->start_pfn set to value to search for and
+ * goes out with active range if it contains it
+ * Returns 1 if search value is in range else 0
+ */
+static int __init get_active_region_work_fn(unsigned long start_pfn,
+ unsigned long end_pfn, void *datax)
+{
+ struct node_active_region *data;
+ data = (struct node_active_region *)datax;
+
+ if (start_pfn <= data->start_pfn && end_pfn > data->start_pfn) {
+ data->start_pfn = start_pfn;
+ data->end_pfn = end_pfn;
+ return 1;
+ }
+ return 0;
+
+}
+
+/*
+ * get_node_active_region - Return active region containing start_pfn
+ * @start_pfn: The page to return the region for.
+ * @node_ar: Returned set to the active region containing start_pfn
+ */
+static void __init get_node_active_region(unsigned long start_pfn,
+ struct node_active_region *node_ar)
+{
+ int nid = early_pfn_to_nid(start_pfn);
+
+ node_ar->nid = nid;
+ node_ar->start_pfn = start_pfn;
+ work_with_active_regions(nid, get_active_region_work_fn, node_ar);
+}
+
static void __cpuinit map_cpu_to_node(int cpu, int node)
{
numa_cpu_lookup_table[cpu] = node;
@@ -150,6 +190,21 @@ static const int *of_get_associativity(struct device_node *dev)
return of_get_property(dev, "ibm,associativity", NULL);
}
+/*
+ * Returns the property linux,drconf-usable-memory if
+ * it exists (the property exists only in kexec/kdump kernels,
+ * added by kexec-tools)
+ */
+static const u32 *of_get_usable_memory(struct device_node *memory)
+{
+ const u32 *prop;
+ u32 len;
+ prop = of_get_property(memory, "linux,drconf-usable-memory", &len);
+ if (!prop || len < sizeof(unsigned int))
+ return 0;
+ return prop;
+}
+
/* Returns nid in the range [0..MAX_NUMNODES-1], or -1 if no useful numa
* info is found.
*/
@@ -487,14 +542,29 @@ static unsigned long __init numa_enforce_memory_limit(unsigned long start,
}
/*
+ * Reads the counter for a given entry in
+ * linux,drconf-usable-memory property
+ */
+static inline int __init read_usm_ranges(const u32 **usm)
+{
+ /*
+ * For each lmb in ibm,dynamic-memory a corresponding
+ * entry in linux,drconf-usable-memory property contains
+ * a counter followed by that many (base, size) duple.
+ * read the counter from linux,drconf-usable-memory
+ */
+ return read_n_cells(n_mem_size_cells, usm);
+}
+
+/*
* Extract NUMA information from the ibm,dynamic-reconfiguration-memory
* node. This assumes n_mem_{addr,size}_cells have been set.
*/
static void __init parse_drconf_memory(struct device_node *memory)
{
- const u32 *dm;
- unsigned int n, rc;
- unsigned long lmb_size, size;
+ const u32 *dm, *usm;
+ unsigned int n, rc, ranges, is_kexec_kdump = 0;
+ unsigned long lmb_size, base, size, sz;
int nid;
struct assoc_arrays aa;
@@ -510,6 +580,11 @@ static void __init parse_drconf_memory(struct device_node *memory)
if (rc)
return;
+ /* check if this is a kexec/kdump kernel */
+ usm = of_get_usable_memory(memory);
+ if (usm != NULL)
+ is_kexec_kdump = 1;
+
for (; n != 0; --n) {
struct of_drconf_cell drmem;
@@ -521,21 +596,31 @@ static void __init parse_drconf_memory(struct device_node *memory)
|| !(drmem.flags & DRCONF_MEM_ASSIGNED))
continue;
- nid = of_drconf_to_nid_single(&drmem, &aa);
+ base = drmem.base_addr;
+ size = lmb_size;
+ ranges = 1;
- fake_numa_create_new_node(
- ((drmem.base_addr + lmb_size) >> PAGE_SHIFT),
+ if (is_kexec_kdump) {
+ ranges = read_usm_ranges(&usm);
+ if (!ranges) /* there are no (base, size) duple */
+ continue;
+ }
+ do {
+ if (is_kexec_kdump) {
+ base = read_n_cells(n_mem_addr_cells, &usm);
+ size = read_n_cells(n_mem_size_cells, &usm);
+ }
+ nid = of_drconf_to_nid_single(&drmem, &aa);
+ fake_numa_create_new_node(
+ ((base + size) >> PAGE_SHIFT),
&nid);
-
- node_set_online(nid);
-
- size = numa_enforce_memory_limit(drmem.base_addr, lmb_size);
- if (!size)
- continue;
-
- add_active_range(nid, drmem.base_addr >> PAGE_SHIFT,
- (drmem.base_addr >> PAGE_SHIFT)
- + (size >> PAGE_SHIFT));
+ node_set_online(nid);
+ sz = numa_enforce_memory_limit(base, size);
+ if (sz)
+ add_active_range(nid, base >> PAGE_SHIFT,
+ (base >> PAGE_SHIFT)
+ + (sz >> PAGE_SHIFT));
+ } while (--ranges);
}
}
@@ -837,38 +922,50 @@ void __init do_init_bootmem(void)
start_pfn, end_pfn);
free_bootmem_with_active_regions(nid, end_pfn);
+ }
- /* Mark reserved regions on this node */
- for (i = 0; i < lmb.reserved.cnt; i++) {
- unsigned long physbase = lmb.reserved.region[i].base;
- unsigned long size = lmb.reserved.region[i].size;
- unsigned long start_paddr = start_pfn << PAGE_SHIFT;
- unsigned long end_paddr = end_pfn << PAGE_SHIFT;
-
- if (early_pfn_to_nid(physbase >> PAGE_SHIFT) != nid &&
- early_pfn_to_nid((physbase+size-1) >> PAGE_SHIFT) != nid)
- continue;
-
- if (physbase < end_paddr &&
- (physbase+size) > start_paddr) {
- /* overlaps */
- if (physbase < start_paddr) {
- size -= start_paddr - physbase;
- physbase = start_paddr;
- }
-
- if (size > end_paddr - physbase)
- size = end_paddr - physbase;
-
- dbg("reserve_bootmem %lx %lx\n", physbase,
- size);
- reserve_bootmem_node(NODE_DATA(nid), physbase,
- size, BOOTMEM_DEFAULT);
- }
+ /* Mark reserved regions */
+ for (i = 0; i < lmb.reserved.cnt; i++) {
+ unsigned long physbase = lmb.reserved.region[i].base;
+ unsigned long size = lmb.reserved.region[i].size;
+ unsigned long start_pfn = physbase >> PAGE_SHIFT;
+ unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT);
+ struct node_active_region node_ar;
+
+ get_node_active_region(start_pfn, &node_ar);
+ while (start_pfn < end_pfn) {
+ /*
+ * if reserved region extends past active region
+ * then trim size to active region
+ */
+ if (end_pfn > node_ar.end_pfn)
+ size = (node_ar.end_pfn << PAGE_SHIFT)
+ - (start_pfn << PAGE_SHIFT);
+ dbg("reserve_bootmem %lx %lx nid=%d\n", physbase, size,
+ node_ar.nid);
+ reserve_bootmem_node(NODE_DATA(node_ar.nid), physbase,
+ size, BOOTMEM_DEFAULT);
+ /*
+ * if reserved region is contained in the active region
+ * then done.
+ */
+ if (end_pfn <= node_ar.end_pfn)
+ break;
+
+ /*
+ * reserved region extends past the active region
+ * get next active region that contains this
+ * reserved region
+ */
+ start_pfn = node_ar.end_pfn;
+ physbase = start_pfn << PAGE_SHIFT;
+ get_node_active_region(start_pfn, &node_ar);
}
- sparse_memory_present_with_active_regions(nid);
}
+
+ for_each_online_node(nid)
+ sparse_memory_present_with_active_regions(nid);
}
void __init paging_init(void)
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c
index 2001abdb191..c31d6d26f0b 100644
--- a/arch/powerpc/mm/pgtable_32.c
+++ b/arch/powerpc/mm/pgtable_32.c
@@ -73,7 +73,7 @@ extern unsigned long p_mapped_by_tlbcam(unsigned long pa);
#endif /* HAVE_TLBCAM */
#ifdef CONFIG_PTE_64BIT
-/* 44x uses an 8kB pgdir because it has 8-byte Linux PTEs. */
+/* Some processors use an 8kB pgdir because they have 8-byte Linux PTEs. */
#define PGDIR_ORDER 1
#else
#define PGDIR_ORDER 0
@@ -288,7 +288,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
}
/*
- * Map in all of physical memory starting at KERNELBASE.
+ * Map in a big chunk of physical memory starting at KERNELBASE.
*/
void __init mapin_ram(void)
{
diff --git a/arch/powerpc/mm/tlb_32.c b/arch/powerpc/mm/tlb_32.c
index eb4b512d65f..f9a47fee392 100644
--- a/arch/powerpc/mm/tlb_32.c
+++ b/arch/powerpc/mm/tlb_32.c
@@ -45,6 +45,7 @@ void flush_hash_entry(struct mm_struct *mm, pte_t *ptep, unsigned long addr)
flush_hash_pages(mm->context.id, addr, ptephys, 1);
}
}
+EXPORT_SYMBOL(flush_hash_entry);
/*
* Called by ptep_set_access_flags, must flush on CPUs for which the
diff --git a/arch/powerpc/oprofile/cell/vma_map.c b/arch/powerpc/oprofile/cell/vma_map.c
index fff66662d02..258fa4411e9 100644
--- a/arch/powerpc/oprofile/cell/vma_map.c
+++ b/arch/powerpc/oprofile/cell/vma_map.c
@@ -229,7 +229,7 @@ struct vma_to_fileoffset_map *create_vma_map(const struct spu *aSpu,
*/
overlay_tbl_offset = vma_map_lookup(map, ovly_table_sym,
aSpu, &grd_val);
- if (overlay_tbl_offset < 0) {
+ if (overlay_tbl_offset > 0x10000000) {
printk(KERN_ERR "SPU_PROF: "
"%s, line %d: Error finding SPU overlay table\n",
__func__, __LINE__);
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 446a8bbb847..3e3d91f536e 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -64,7 +64,7 @@ static int power4_reg_setup(struct op_counter_config *ctr,
return 0;
}
-extern void ppc64_enable_pmcs(void);
+extern void ppc_enable_pmcs(void);
/*
* Older CPUs require the MMCRA sample bit to be always set, but newer
@@ -91,7 +91,7 @@ static int power4_cpu_setup(struct op_counter_config *ctr)
unsigned int mmcr0 = mmcr0_val;
unsigned long mmcra = mmcra_val;
- ppc64_enable_pmcs();
+ ppc_enable_pmcs();
/* set the freeze bit */
mmcr0 |= MMCR0_FC;
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig
index 249ba01c667..79c1154f88d 100644
--- a/arch/powerpc/platforms/44x/Kconfig
+++ b/arch/powerpc/platforms/44x/Kconfig
@@ -2,6 +2,7 @@ config BAMBOO
bool "Bamboo"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440EP
select PCI
help
@@ -30,6 +31,7 @@ config SEQUOIA
bool "Sequoia"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440EPX
help
This option enables support for the AMCC PPC440EPX evaluation board.
@@ -38,6 +40,7 @@ config TAISHAN
bool "Taishan"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440GX
select PCI
help
@@ -48,6 +51,7 @@ config KATMAI
bool "Katmai"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440SPe
select PCI
select PPC4xx_PCI_EXPRESS
@@ -58,6 +62,7 @@ config RAINIER
bool "Rainier"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440GRX
select PCI
help
@@ -76,20 +81,48 @@ config WARP
See http://www.pikatechnologies.com/ and follow the "PIKA for Computer
Telephony Developers" link for more information.
+config ARCHES
+ bool "Arches"
+ depends on 44x
+ default n
+ select PPC44x_SIMPLE
+ select 460EX # Odd since it uses 460GT but the effects are the same
+ select PCI
+ select PPC4xx_PCI_EXPRESS
+ help
+ This option enables support for the AMCC Dual PPC460GT evaluation board.
+
config CANYONLANDS
bool "Canyonlands"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 460EX
select PCI
select PPC4xx_PCI_EXPRESS
+ select IBM_NEW_EMAC_RGMII
+ select IBM_NEW_EMAC_ZMII
help
This option enables support for the AMCC PPC460EX evaluation board.
+config GLACIER
+ bool "Glacier"
+ depends on 44x
+ default n
+ select PPC44x_SIMPLE
+ select 460EX # Odd since it uses 460GT but the effects are the same
+ select PCI
+ select PPC4xx_PCI_EXPRESS
+ select IBM_NEW_EMAC_RGMII
+ select IBM_NEW_EMAC_ZMII
+ help
+ This option enables support for the AMCC PPC460GT evaluation board.
+
config YOSEMITE
bool "Yosemite"
depends on 44x
default n
+ select PPC44x_SIMPLE
select 440EP
select PCI
help
@@ -127,6 +160,13 @@ config XILINX_VIRTEX440_GENERIC_BOARD
Most Virtex 5 designs should use this unless it needs to do some
special configuration at board probe time.
+config PPC44x_SIMPLE
+ bool "Simple PowerPC 44x board support"
+ depends on 44x
+ default n
+ help
+ This option enables the simple PowerPC 44x platform support.
+
# 44x specific CPU modules, selected based on the board above.
config 440EP
bool
@@ -170,8 +210,6 @@ config 460EX
bool
select PPC_FPU
select IBM_NEW_EMAC_EMAC4
- select IBM_NEW_EMAC_RGMII
- select IBM_NEW_EMAC_ZMII
select IBM_NEW_EMAC_TAH
# 44x errata/workaround config symbols, selected by the CPU models above
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile
index 8d0b1a192d6..698133180ae 100644
--- a/arch/powerpc/platforms/44x/Makefile
+++ b/arch/powerpc/platforms/44x/Makefile
@@ -1,13 +1,7 @@
obj-$(CONFIG_44x) := misc_44x.o idle.o
+obj-$(CONFIG_PPC44x_SIMPLE) += ppc44x_simple.o
obj-$(CONFIG_EBONY) += ebony.o
-obj-$(CONFIG_TAISHAN) += taishan.o
-obj-$(CONFIG_BAMBOO) += bamboo.o
-obj-$(CONFIG_YOSEMITE) += bamboo.o
obj-$(CONFIG_SAM440EP) += sam440ep.o
-obj-$(CONFIG_SEQUOIA) += sequoia.o
-obj-$(CONFIG_KATMAI) += katmai.o
-obj-$(CONFIG_RAINIER) += rainier.o
obj-$(CONFIG_WARP) += warp.o
obj-$(CONFIG_WARP) += warp-nand.o
-obj-$(CONFIG_CANYONLANDS) += canyonlands.o
obj-$(CONFIG_XILINX_VIRTEX_5_FXT) += virtex.o
diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c
deleted file mode 100644
index cef169e9515..00000000000
--- a/arch/powerpc/platforms/44x/bamboo.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Bamboo board specific routines
- *
- * Wade Farnsworth <wfarnsworth@mvista.com>
- * Copyright 2004 MontaVista Software Inc.
- *
- * Rewritten and ported to the merged powerpc tree:
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id bamboo_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init bamboo_device_probe(void)
-{
- of_platform_bus_probe(NULL, bamboo_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(bamboo, bamboo_device_probe);
-
-static int __init bamboo_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,bamboo"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(bamboo) {
- .name = "Bamboo",
- .probe = bamboo_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/canyonlands.c b/arch/powerpc/platforms/44x/canyonlands.c
deleted file mode 100644
index 3949289f51d..00000000000
--- a/arch/powerpc/platforms/44x/canyonlands.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Canyonlands board specific routines
- *
- * Copyright 2008 DENX Software Engineering, Stefan Roese <sr@denx.de>
- *
- * Based on the Katmai code by
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- * Copyright 2007 IBM Corp.
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id canyonlands_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init canyonlands_device_probe(void)
-{
- of_platform_bus_probe(NULL, canyonlands_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(canyonlands, canyonlands_device_probe);
-
-static int __init canyonlands_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,canyonlands"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(canyonlands) {
- .name = "Canyonlands",
- .probe = canyonlands_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/katmai.c b/arch/powerpc/platforms/44x/katmai.c
deleted file mode 100644
index 44f4b3a00ce..00000000000
--- a/arch/powerpc/platforms/44x/katmai.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Katmai board specific routines
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- * Copyright 2007 IBM Corp.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id katmai_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init katmai_device_probe(void)
-{
- of_platform_bus_probe(NULL, katmai_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(katmai, katmai_device_probe);
-
-static int __init katmai_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,katmai"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(katmai) {
- .name = "Katmai",
- .probe = katmai_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c
new file mode 100644
index 00000000000..29671262801
--- /dev/null
+++ b/arch/powerpc/platforms/44x/ppc44x_simple.c
@@ -0,0 +1,88 @@
+/*
+ * Generic PowerPC 44x platform support
+ *
+ * Copyright 2008 IBM Corporation
+ *
+ * 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 implements simple platform support for PowerPC 44x chips. This is
+ * mostly used for eval boards or other simple and "generic" 44x boards. If
+ * your board has custom functions or hardware, then you will likely want to
+ * implement your own board.c file to accommodate it.
+ */
+
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/ppc4xx.h>
+#include <asm/prom.h>
+#include <asm/time.h>
+#include <asm/udbg.h>
+#include <asm/uic.h>
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+
+static __initdata struct of_device_id ppc44x_of_bus[] = {
+ { .compatible = "ibm,plb4", },
+ { .compatible = "ibm,opb", },
+ { .compatible = "ibm,ebc", },
+ { .compatible = "simple-bus", },
+ {},
+};
+
+static int __init ppc44x_device_probe(void)
+{
+ of_platform_bus_probe(NULL, ppc44x_of_bus, NULL);
+
+ return 0;
+}
+machine_device_initcall(ppc44x_simple, ppc44x_device_probe);
+
+/* This is the list of boards that can be supported by this simple
+ * platform code. This does _not_ mean the boards are compatible,
+ * as they most certainly are not from a device tree perspective.
+ * However, their differences are handled by the device tree and the
+ * drivers and therefore they don't need custom board support files.
+ *
+ * Again, if your board needs to do things differently then create a
+ * board.c file for it rather than adding it to this list.
+ */
+static char *board[] __initdata = {
+ "amcc,arches",
+ "amcc,bamboo",
+ "amcc,canyonlands",
+ "amcc,glacier",
+ "ibm,ebony",
+ "amcc,katmai",
+ "amcc,rainier",
+ "amcc,sequoia",
+ "amcc,taishan",
+ "amcc,yosemite"
+};
+
+static int __init ppc44x_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+ int i = 0;
+
+ for (i = 0; i < ARRAY_SIZE(board); i++) {
+ if (of_flat_dt_is_compatible(root, board[i])) {
+ ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+define_machine(ppc44x_simple) {
+ .name = "PowerPC 44x Platform",
+ .probe = ppc44x_probe,
+ .progress = udbg_progress,
+ .init_IRQ = uic_init_tree,
+ .get_irq = uic_get_irq,
+ .restart = ppc4xx_reset_system,
+ .calibrate_decr = generic_calibrate_decr,
+};
diff --git a/arch/powerpc/platforms/44x/rainier.c b/arch/powerpc/platforms/44x/rainier.c
deleted file mode 100644
index 4f1ff84c4b6..00000000000
--- a/arch/powerpc/platforms/44x/rainier.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Rainier board specific routines
- *
- * Valentine Barshak <vbarshak@ru.mvista.com>
- * Copyright 2007 MontaVista Software Inc.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id rainier_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init rainier_device_probe(void)
-{
- of_platform_bus_probe(NULL, rainier_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(rainier, rainier_device_probe);
-
-static int __init rainier_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,rainier"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(rainier) {
- .name = "Rainier",
- .probe = rainier_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c
deleted file mode 100644
index 49eb73daacd..00000000000
--- a/arch/powerpc/platforms/44x/sequoia.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Sequoia board specific routines
- *
- * Valentine Barshak <vbarshak@ru.mvista.com>
- * Copyright 2007 MontaVista Software Inc.
- *
- * Based on the Bamboo code by
- * Josh Boyer <jwboyer@linux.vnet.ibm.com>
- * Copyright 2007 IBM Corporation
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id sequoia_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init sequoia_device_probe(void)
-{
- of_platform_bus_probe(NULL, sequoia_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(sequoia, sequoia_device_probe);
-
-static int __init sequoia_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,sequoia"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(sequoia) {
- .name = "Sequoia",
- .probe = sequoia_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/44x/taishan.c b/arch/powerpc/platforms/44x/taishan.c
deleted file mode 100644
index 49c78b2098b..00000000000
--- a/arch/powerpc/platforms/44x/taishan.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Taishan board specific routines based off ebony.c code
- * original copyrights below
- *
- * Matt Porter <mporter@kernel.crashing.org>
- * Copyright 2002-2005 MontaVista Software Inc.
- *
- * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
- * Copyright (c) 2003-2005 Zultys Technologies
- *
- * Rewritten and ported to the merged powerpc tree:
- * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
- *
- * Modified from ebony.c for taishan:
- * Copyright 2007 Hugh Blemings <hugh@au.ibm.com>, IBM Corporation.
- *
- * 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/of_platform.h>
-
-#include <asm/machdep.h>
-#include <asm/prom.h>
-#include <asm/udbg.h>
-#include <asm/time.h>
-#include <asm/uic.h>
-#include <asm/pci-bridge.h>
-#include <asm/ppc4xx.h>
-
-static __initdata struct of_device_id taishan_of_bus[] = {
- { .compatible = "ibm,plb4", },
- { .compatible = "ibm,opb", },
- { .compatible = "ibm,ebc", },
- {},
-};
-
-static int __init taishan_device_probe(void)
-{
- of_platform_bus_probe(NULL, taishan_of_bus, NULL);
-
- return 0;
-}
-machine_device_initcall(taishan, taishan_device_probe);
-
-/*
- * Called very early, MMU is off, device-tree isn't unflattened
- */
-static int __init taishan_probe(void)
-{
- unsigned long root = of_get_flat_dt_root();
-
- if (!of_flat_dt_is_compatible(root, "amcc,taishan"))
- return 0;
-
- ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
-
- return 1;
-}
-
-define_machine(taishan) {
- .name = "Taishan",
- .probe = taishan_probe,
- .progress = udbg_progress,
- .init_IRQ = uic_init_tree,
- .get_irq = uic_get_irq,
- .restart = ppc4xx_reset_system,
- .calibrate_decr = generic_calibrate_decr,
-};
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index c62f893ede1..326852c78b8 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -3,6 +3,8 @@ config PPC_MPC512x
select FSL_SOC
select IPIC
select PPC_CLOCK
+ select PPC_PCI_CHOICE
+ select FSL_PCI if PCI
config PPC_MPC5121
bool
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 5ebf6939a69..441abc48885 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -22,16 +22,26 @@
#include <asm/prom.h>
#include <asm/time.h>
+#include <sysdev/fsl_pci.h>
+
#include "mpc512x.h"
#include "mpc5121_ads.h"
static void __init mpc5121_ads_setup_arch(void)
{
+#ifdef CONFIG_PCI
+ struct device_node *np;
+#endif
printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n");
/*
* cpld regs are needed early
*/
mpc5121_ads_cpld_map();
+
+#ifdef CONFIG_PCI
+ for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
+ mpc83xx_add_bridge(np);
+#endif
}
static void __init mpc5121_ads_init_IRQ(void)
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c
index 4d5fd1dbd40..044b4e6e874 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_common.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c
@@ -90,7 +90,7 @@ mpc5200_setup_xlb_arbiter(void)
of_node_put(np);
if (!xlb) {
printk(KERN_ERR __FILE__ ": "
- "Error mapping XLB in mpc52xx_setup_cpu(). "
+ "Error mapping XLB in mpc52xx_setup_cpu(). "
"Expect some abnormal behavior\n");
return;
}
@@ -216,7 +216,8 @@ mpc52xx_restart(char *cmd)
out_be32(&mpc52xx_wdt->count, 0x000000ff);
out_be32(&mpc52xx_wdt->mode, 0x00009004);
} else
- printk("mpc52xx_restart: Can't access wdt. "
+ printk(KERN_ERR __FILE__ ": "
+ "mpc52xx_restart: Can't access wdt. "
"Restart impossible, system halted.\n");
while (1);
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
index 5a382bb15f6..b49a1852766 100644
--- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -265,8 +265,11 @@ mpc52xx_pci_setup(struct pci_controller *hose,
/* Memory windows */
res = &hose->mem_resources[0];
if (res->flags) {
- pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
- res->start, res->end, res->flags);
+ pr_debug("mem_resource[0] = "
+ "{.start=%llx, .end=%llx, .flags=%llx}\n",
+ (unsigned long long)res->start,
+ (unsigned long long)res->end,
+ (unsigned long long)res->flags);
out_be32(&pci_regs->iw0btar,
MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
res->end - res->start + 1));
@@ -297,9 +300,11 @@ mpc52xx_pci_setup(struct pci_controller *hose,
printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
return;
}
- pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
+ pr_debug(".io_resource={.start=%llx,.end=%llx,.flags=%llx} "
".io_base_phys=0x%p\n",
- res->start, res->end, res->flags, (void*)hose->io_base_phys);
+ (unsigned long long)res->start,
+ (unsigned long long)res->end,
+ (unsigned long long)res->flags, (void*)hose->io_base_phys);
out_be32(&pci_regs->iw2btar,
MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
res->start,
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
index 75eb1ede549..30f008b2f92 100644
--- a/arch/powerpc/platforms/82xx/Kconfig
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -38,6 +38,14 @@ config EP8248E
This board is also resold by Freescale as the QUICCStart
MPC8248 Evaluation System and/or the CWH-PPC-8248N-VE.
+config MGCOGE
+ bool "Keymile MGCOGE"
+ select 8272
+ select 8260
+ select FSL_SOC
+ help
+ This enables support for the Keymile MGCOGE board.
+
endif
config PQ2ADS
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile
index 6cd5cd59bf2..d982793f4db 100644
--- a/arch/powerpc/platforms/82xx/Makefile
+++ b/arch/powerpc/platforms/82xx/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_CPM2) += pq2.o
obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o
obj-$(CONFIG_PQ2FADS) += pq2fads.o
obj-$(CONFIG_EP8248E) += ep8248e.o
+obj-$(CONFIG_MGCOGE) += mgcoge.o
diff --git a/arch/powerpc/platforms/82xx/mgcoge.c b/arch/powerpc/platforms/82xx/mgcoge.c
new file mode 100644
index 00000000000..c2af169c1d1
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/mgcoge.c
@@ -0,0 +1,129 @@
+/*
+ * Keymile mgcoge support
+ * Copyright 2008 DENX Software Engineering GmbH
+ * Author: Heiko Schocher <hs@denx.de>
+ *
+ * based on code from:
+ * Copyright 2007 Freescale Semiconductor, Inc.
+ * Author: Scott Wood <scottwood@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/mpc8260.h>
+#include <asm/prom.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/cpm2_pic.h>
+
+#include "pq2.h"
+
+static void __init mgcoge_pic_init(void)
+{
+ struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic");
+ if (!np) {
+ printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+ return;
+ }
+
+ cpm2_pic_init(np);
+ of_node_put(np);
+}
+
+struct cpm_pin {
+ int port, pin, flags;
+};
+
+static __initdata struct cpm_pin mgcoge_pins[] = {
+
+ /* SMC2 */
+ {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {1, 9, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+
+ /* SCC4 */
+ {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {3, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {3, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {3, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {4, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
+ {4, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
+};
+
+static void __init init_ioports(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mgcoge_pins); i++) {
+ const struct cpm_pin *pin = &mgcoge_pins[i];
+ cpm2_set_pin(pin->port - 1, pin->pin, pin->flags);
+ }
+
+ cpm2_smc_clk_setup(CPM_CLK_SMC2, CPM_BRG8);
+ cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK7, CPM_CLK_RX);
+ cpm2_clk_setup(CPM_CLK_SCC4, CPM_CLK8, CPM_CLK_TX);
+}
+
+static void __init mgcoge_setup_arch(void)
+{
+ if (ppc_md.progress)
+ ppc_md.progress("mgcoge_setup_arch()", 0);
+
+ cpm2_reset();
+
+ /* When this is set, snooping CPM DMA from RAM causes
+ * machine checks. See erratum SIU18.
+ */
+ clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP);
+
+ init_ioports();
+
+ if (ppc_md.progress)
+ ppc_md.progress("mgcoge_setup_arch(), finish", 0);
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+ { .compatible = "simple-bus", },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+ return 0;
+}
+machine_device_initcall(mgcoge, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mgcoge_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+ return of_flat_dt_is_compatible(root, "keymile,mgcoge");
+}
+
+define_machine(mgcoge)
+{
+ .name = "Keymile MGCOGE",
+ .probe = mgcoge_probe,
+ .setup_arch = mgcoge_setup_arch,
+ .init_IRQ = mgcoge_pic_init,
+ .get_irq = cpm2_get_irq,
+ .calibrate_decr = generic_calibrate_decr,
+ .restart = pq2_restart,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 6159c5d4e5f..83c664afc89 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -19,7 +19,6 @@ config MPC831x_RDB
config MPC832x_MDS
bool "Freescale MPC832x MDS"
select DEFAULT_UIMAGE
- select QUICC_ENGINE
select PPC_MPC832x
help
This option enables support for the MPC832x MDS evaluation board.
@@ -27,7 +26,6 @@ config MPC832x_MDS
config MPC832x_RDB
bool "Freescale MPC832x RDB"
select DEFAULT_UIMAGE
- select QUICC_ENGINE
select PPC_MPC832x
help
This option enables support for the MPC8323 RDB board.
@@ -57,15 +55,12 @@ config MPC834x_ITX
config MPC836x_MDS
bool "Freescale MPC836x MDS"
select DEFAULT_UIMAGE
- select QUICC_ENGINE
help
This option enables support for the MPC836x MDS Processor Board.
config MPC836x_RDK
bool "Freescale/Logic MPC836x RDK"
select DEFAULT_UIMAGE
- select QUICC_ENGINE
- select QE_GPIO
select FSL_GTM
select FSL_LBC
help
diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c
index be62de23bea..8bb13c80714 100644
--- a/arch/powerpc/platforms/83xx/mpc837x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c
@@ -85,8 +85,14 @@ static void __init mpc837x_mds_setup_arch(void)
ppc_md.progress("mpc837x_mds_setup_arch()", 0);
#ifdef CONFIG_PCI
- for_each_compatible_node(np, "pci", "fsl,mpc8349-pci")
+ for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") {
+ if (!of_device_is_available(np)) {
+ pr_warning("%s: disabled by the firmware.\n",
+ np->full_name);
+ continue;
+ }
mpc83xx_add_bridge(np);
+ }
#endif
mpc837xmds_usb_cfg();
}
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 291675b0097..b79dc710ed3 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -33,7 +33,6 @@ config MPC85xx_CDS
config MPC85xx_MDS
bool "Freescale MPC85xx MDS"
select DEFAULT_UIMAGE
- select QUICC_ENGINE
select PHYLIB
help
This option enables support for the MPC85xx MDS board
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index d17807a6b89..0293e3d3580 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -213,7 +213,6 @@ static void mpc85xx_ads_show_cpuinfo(struct seq_file *m)
svid = mfspr(SPRN_SVR);
seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
- seq_printf(m, "Machine\t\t: mpc85xx\n");
seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
seq_printf(m, "SVR\t\t: 0x%x\n", svid);
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
index 6509ade7166..0c9a856f66b 100644
--- a/arch/powerpc/platforms/85xx/sbc8560.c
+++ b/arch/powerpc/platforms/85xx/sbc8560.c
@@ -156,7 +156,7 @@ static void __init init_ioports(void)
int i;
for (i = 0; i < ARRAY_SIZE(sbc8560_pins); i++) {
- struct cpm_pin *pin = &sbc8560_pins[i];
+ const struct cpm_pin *pin = &sbc8560_pins[i];
cpm2_set_pin(pin->port, pin->pin, pin->flags);
}
@@ -200,7 +200,6 @@ static void sbc8560_show_cpuinfo(struct seq_file *m)
svid = mfspr(SPRN_SVR);
seq_printf(m, "Vendor\t\t: Wind River\n");
- seq_printf(m, "Machine\t\t: SBC8560\n");
seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
seq_printf(m, "SVR\t\t: 0x%x\n", svid);
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index 9355a526943..77dd797a258 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -31,6 +31,13 @@ config MPC8610_HPCD
help
This option enables support for the MPC8610 HPCD board.
+config GEF_SBC610
+ bool "GE Fanuc SBC610"
+ select DEFAULT_UIMAGE
+ select HAS_RAPIDIO
+ help
+ This option enables support for GE Fanuc's SBC610.
+
endif
config MPC8641
@@ -39,7 +46,7 @@ config MPC8641
select FSL_PCI if PCI
select PPC_UDBG_16550
select MPIC
- default y if MPC8641_HPCN || SBC8641D
+ default y if MPC8641_HPCN || SBC8641D || GEF_SBC610
config MPC8610
bool
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile
index 8fee37dec79..4a56ff619af 100644
--- a/arch/powerpc/platforms/86xx/Makefile
+++ b/arch/powerpc/platforms/86xx/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o
obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o
obj-$(CONFIG_SBC8641D) += sbc8641d.o
obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o
+obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
new file mode 100644
index 00000000000..50d0a2b6380
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_pic.c
@@ -0,0 +1,258 @@
+/*
+ * Interrupt handling for GE Fanuc's FPGA based PIC
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * 2008 (c) GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/irq.h>
+
+#include "gef_pic.h"
+
+#define DEBUG
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
+#else
+#define DBG(fmt...) do { } while (0)
+#endif
+
+#define GEF_PIC_NUM_IRQS 32
+
+/* Interrupt Controller Interface Registers */
+#define GEF_PIC_INTR_STATUS 0x0000
+
+#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
+#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
+#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
+
+#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
+#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
+#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
+
+#define gef_irq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
+
+
+static DEFINE_SPINLOCK(gef_pic_lock);
+
+static void __iomem *gef_pic_irq_reg_base;
+static struct irq_host *gef_pic_irq_host;
+static int gef_pic_cascade_irq;
+
+/*
+ * Interrupt Controller Handling
+ *
+ * The interrupt controller handles interrupts for most on board interrupts,
+ * apart from PCI interrupts. For example on SBC610:
+ *
+ * 17:31 RO Reserved
+ * 16 RO PCI Express Doorbell 3 Status
+ * 15 RO PCI Express Doorbell 2 Status
+ * 14 RO PCI Express Doorbell 1 Status
+ * 13 RO PCI Express Doorbell 0 Status
+ * 12 RO Real Time Clock Interrupt Status
+ * 11 RO Temperature Interrupt Status
+ * 10 RO Temperature Critical Interrupt Status
+ * 9 RO Ethernet PHY1 Interrupt Status
+ * 8 RO Ethernet PHY3 Interrupt Status
+ * 7 RO PEX8548 Interrupt Status
+ * 6 RO Reserved
+ * 5 RO Watchdog 0 Interrupt Status
+ * 4 RO Watchdog 1 Interrupt Status
+ * 3 RO AXIS Message FIFO A Interrupt Status
+ * 2 RO AXIS Message FIFO B Interrupt Status
+ * 1 RO AXIS Message FIFO C Interrupt Status
+ * 0 RO AXIS Message FIFO D Interrupt Status
+ *
+ * Interrupts can be forwarded to one of two output lines. Nothing
+ * clever is done, so if the masks are incorrectly set, a single input
+ * interrupt could generate interrupts on both output lines!
+ *
+ * The dual lines are there to allow the chained interrupts to be easily
+ * passed into two different cores. We currently do not use this functionality
+ * in this driver.
+ *
+ * Controller can also be configured to generate Machine checks (MCP), again on
+ * two lines, to be attached to two different cores. It is suggested that these
+ * should be masked out.
+ */
+
+void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int cascade_irq;
+
+ /*
+ * See if we actually have an interrupt, call generic handling code if
+ * we do.
+ */
+ cascade_irq = gef_pic_get_irq();
+
+ if (cascade_irq != NO_IRQ)
+ generic_handle_irq(cascade_irq);
+
+ desc->chip->eoi(irq);
+
+}
+
+static void gef_pic_mask(unsigned int virq)
+{
+ unsigned long flags;
+ unsigned int hwirq;
+ u32 mask;
+
+ hwirq = gef_irq_to_hw(virq);
+
+ spin_lock_irqsave(&gef_pic_lock, flags);
+ mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+ mask &= ~(1 << hwirq);
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+ spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static void gef_pic_mask_ack(unsigned int virq)
+{
+ /* Don't think we actually have to do anything to ack an interrupt,
+ * we just need to clear down the devices interrupt and it will go away
+ */
+ gef_pic_mask(virq);
+}
+
+static void gef_pic_unmask(unsigned int virq)
+{
+ unsigned long flags;
+ unsigned int hwirq;
+ u32 mask;
+
+ hwirq = gef_irq_to_hw(virq);
+
+ spin_lock_irqsave(&gef_pic_lock, flags);
+ mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+ mask |= (1 << hwirq);
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
+ spin_unlock_irqrestore(&gef_pic_lock, flags);
+}
+
+static struct irq_chip gef_pic_chip = {
+ .typename = "gefp",
+ .mask = gef_pic_mask,
+ .mask_ack = gef_pic_mask_ack,
+ .unmask = gef_pic_unmask,
+};
+
+
+/* When an interrupt is being configured, this call allows some flexibilty
+ * in deciding which irq_chip structure is used
+ */
+static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hwirq)
+{
+ /* All interrupts are LEVEL sensitive */
+ get_irq_desc(virq)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
+
+ return 0;
+}
+
+static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+ u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+
+ *out_hwirq = intspec[0];
+ if (intsize > 1)
+ *out_flags = intspec[1];
+ else
+ *out_flags = IRQ_TYPE_LEVEL_HIGH;
+
+ return 0;
+}
+
+static struct irq_host_ops gef_pic_host_ops = {
+ .map = gef_pic_host_map,
+ .xlate = gef_pic_host_xlate,
+};
+
+
+/*
+ * Initialisation of PIC, this should be called in BSP
+ */
+void __init gef_pic_init(struct device_node *np)
+{
+ unsigned long flags;
+
+ /* Map the devices registers into memory */
+ gef_pic_irq_reg_base = of_iomap(np, 0);
+
+ spin_lock_irqsave(&gef_pic_lock, flags);
+
+ /* Initialise everything as masked. */
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
+
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
+ out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
+
+ spin_unlock_irqrestore(&gef_pic_lock, flags);
+
+ /* Map controller */
+ gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
+ if (gef_pic_cascade_irq == NO_IRQ) {
+ printk(KERN_ERR "SBC610: failed to map cascade interrupt");
+ return;
+ }
+
+ /* Setup an irq_host structure */
+ gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
+ GEF_PIC_NUM_IRQS,
+ &gef_pic_host_ops, NO_IRQ);
+ if (gef_pic_irq_host == NULL)
+ return;
+
+ /* Chain with parent controller */
+ set_irq_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
+}
+
+/*
+ * This is called when we receive an interrupt with apparently comes from this
+ * chip - check, returning the highest interrupt generated or return NO_IRQ
+ */
+unsigned int gef_pic_get_irq(void)
+{
+ u32 cause, mask, active;
+ unsigned int virq = NO_IRQ;
+ int hwirq;
+
+ cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
+
+ mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
+
+ active = cause & mask;
+
+ if (active) {
+ for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
+ if (active & (0x1 << hwirq))
+ break;
+ }
+ virq = irq_linear_revmap(gef_pic_irq_host,
+ (irq_hw_number_t)hwirq);
+ }
+
+ return virq;
+}
+
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h
new file mode 100644
index 00000000000..6149916da3f
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_pic.h
@@ -0,0 +1,11 @@
+#ifndef __GEF_PIC_H__
+#define __GEF_PIC_H__
+
+#include <linux/init.h>
+
+void gef_pic_cascade(unsigned int, struct irq_desc *);
+unsigned int gef_pic_get_irq(void);
+void gef_pic_init(struct device_node *);
+
+#endif /* __GEF_PIC_H__ */
+
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c
new file mode 100644
index 00000000000..821c45fac18
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_sbc610.c
@@ -0,0 +1,221 @@
+/*
+ * GE Fanuc SBC610 board support
+ *
+ * Author: Martyn Welch <martyn.welch@gefanuc.com>
+ *
+ * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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.
+ *
+ * Based on: mpc86xx_hpcn.c (MPC86xx HPCN board specific routines)
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * NEC fixup adapted from arch/mips/pci/fixup-lm2e.c
+ */
+
+#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/of_platform.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/mpic.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+#include "gef_pic.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG (fmt...) do { printk(KERN_ERR "SBC610: " fmt); } while (0)
+#else
+#define DBG (fmt...) do { } while (0)
+#endif
+
+void __iomem *sbc610_regs;
+
+static void __init gef_sbc610_init_irq(void)
+{
+ struct device_node *cascade_node = NULL;
+
+ mpc86xx_init_irq();
+
+ /*
+ * There is a simple interrupt handler in the main FPGA, this needs
+ * to be cascaded into the MPIC
+ */
+ cascade_node = of_find_compatible_node(NULL, NULL, "gef,fpga-pic");
+ if (!cascade_node) {
+ printk(KERN_WARNING "SBC610: No FPGA PIC\n");
+ return;
+ }
+
+ gef_pic_init(cascade_node);
+ of_node_put(cascade_node);
+}
+
+static void __init gef_sbc610_setup_arch(void)
+{
+ struct device_node *regs;
+#ifdef CONFIG_PCI
+ struct device_node *np;
+
+ for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") {
+ fsl_add_bridge(np, 1);
+ }
+#endif
+
+ printk(KERN_INFO "GE Fanuc Intelligent Platforms SBC610 6U VPX SBC\n");
+
+#ifdef CONFIG_SMP
+ mpc86xx_smp_init();
+#endif
+
+ /* Remap basic board registers */
+ regs = of_find_compatible_node(NULL, NULL, "gef,fpga-regs");
+ if (regs) {
+ sbc610_regs = of_iomap(regs, 0);
+ if (sbc610_regs == NULL)
+ printk(KERN_WARNING "Unable to map board registers\n");
+ of_node_put(regs);
+ }
+}
+
+/* Return the PCB revision */
+static unsigned int gef_sbc610_get_pcb_rev(void)
+{
+ unsigned int reg;
+
+ reg = ioread32(sbc610_regs);
+ return (reg >> 8) & 0xff;
+}
+
+/* Return the board (software) revision */
+static unsigned int gef_sbc610_get_board_rev(void)
+{
+ unsigned int reg;
+
+ reg = ioread32(sbc610_regs);
+ return (reg >> 16) & 0xff;
+}
+
+/* Return the FPGA revision */
+static unsigned int gef_sbc610_get_fpga_rev(void)
+{
+ unsigned int reg;
+
+ reg = ioread32(sbc610_regs);
+ return (reg >> 24) & 0xf;
+}
+
+static void gef_sbc610_show_cpuinfo(struct seq_file *m)
+{
+ uint memsize = total_memory;
+ uint svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: GE Fanuc Intelligent Platforms\n");
+
+ seq_printf(m, "Revision\t: %u%c\n", gef_sbc610_get_pcb_rev(),
+ ('A' + gef_sbc610_get_board_rev() - 1));
+ seq_printf(m, "FPGA Revision\t: %u\n", gef_sbc610_get_fpga_rev());
+
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
+
+static void __init gef_sbc610_nec_fixup(struct pci_dev *pdev)
+{
+ unsigned int val;
+
+ printk(KERN_INFO "Running NEC uPD720101 Fixup\n");
+
+ /* Ensure ports 1, 2, 3, 4 & 5 are enabled */
+ pci_read_config_dword(pdev, 0xe0, &val);
+ pci_write_config_dword(pdev, 0xe0, (val & ~7) | 0x5);
+
+ /* System clock is 48-MHz Oscillator and EHCI Enabled. */
+ pci_write_config_dword(pdev, 0xe4, 1 << 5);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB,
+ gef_sbc610_nec_fixup);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ *
+ * This function is called to determine whether the BSP is compatible with the
+ * supplied device-tree, which is assumed to be the correct one for the actual
+ * board. It is expected thati, in the future, a kernel may support multiple
+ * boards.
+ */
+static int __init gef_sbc610_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+
+ if (of_flat_dt_is_compatible(root, "gef,sbc610"))
+ return 1;
+
+ return 0;
+}
+
+static 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;
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+ { .compatible = "simple-bus", },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ printk(KERN_DEBUG "Probe platform devices\n");
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+ return 0;
+}
+machine_device_initcall(gef_sbc610, declare_of_platform_devices);
+
+define_machine(gef_sbc610) {
+ .name = "GE Fanuc SBC610",
+ .probe = gef_sbc610_probe,
+ .setup_arch = gef_sbc610_setup_arch,
+ .init_IRQ = gef_sbc610_init_irq,
+ .show_cpuinfo = gef_sbc610_show_cpuinfo,
+ .get_irq = mpic_get_irq,
+ .restart = fsl_rstcr_restart,
+ .time_init = mpc86xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+#ifdef CONFIG_PCI
+ .pcibios_fixup_bus = fsl_pcibios_fixup_bus,
+#endif
+};
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
index 5eedb710896..e8d54ac5292 100644
--- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
+++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c
@@ -238,7 +238,6 @@ static void __init mpc86xx_hpcd_setup_arch(void)
}
#endif
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
- preallocate_diu_videomemory();
diu_ops.get_pixel_format = mpc8610hpcd_get_pixel_format;
diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table;
diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port;
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index f712d9c0991..2672829a71d 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -101,19 +101,11 @@ mpc86xx_hpcn_setup_arch(void)
static 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 = of_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));
}
diff --git a/arch/powerpc/platforms/86xx/sbc8641d.c b/arch/powerpc/platforms/86xx/sbc8641d.c
index 00e6fad3b3c..da677a74e2d 100644
--- a/arch/powerpc/platforms/86xx/sbc8641d.c
+++ b/arch/powerpc/platforms/86xx/sbc8641d.c
@@ -63,19 +63,11 @@ sbc8641_setup_arch(void)
static void
sbc8641_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: Wind River Systems\n");
- root = of_find_node_by_path("/");
- if (root)
- model = of_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));
}
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index 71d7562e190..48a920a98e7 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -49,6 +49,12 @@ config PPC_ADDER875
This enables support for the Analogue & Micro Adder 875
board.
+config PPC_MGSUVD
+ bool "MGSUVD"
+ select CPM1
+ help
+ This enables support for the Keymile MGSUVD board.
+
endchoice
menu "Freescale Ethernet driver platform-specific options"
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
index 7b71d9c8fb4..bdbfd749601 100644
--- a/arch/powerpc/platforms/8xx/Makefile
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
obj-$(CONFIG_PPC_EP88XC) += ep88xc.o
obj-$(CONFIG_PPC_ADDER875) += adder875.o
+obj-$(CONFIG_PPC_MGSUVD) += mgsuvd.o
diff --git a/arch/powerpc/platforms/8xx/mgsuvd.c b/arch/powerpc/platforms/8xx/mgsuvd.c
new file mode 100644
index 00000000000..ca3cb071772
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mgsuvd.c
@@ -0,0 +1,92 @@
+/*
+ *
+ * Platform setup for the Keymile mgsuvd board
+ *
+ * Heiko Schocher <hs@denx.de>
+ *
+ * Copyright 2008 DENX Software Engineering GmbH
+ *
+ * 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/ioport.h>
+#include <linux/of_platform.h>
+
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/processor.h>
+#include <asm/cpm1.h>
+#include <asm/prom.h>
+#include <asm/fs_pd.h>
+
+#include "mpc8xx.h"
+
+struct cpm_pin {
+ int port, pin, flags;
+};
+
+static __initdata struct cpm_pin mgsuvd_pins[] = {
+ /* SMC1 */
+ {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */
+ {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */
+
+ /* SCC3 */
+ {CPM_PORTA, 10, CPM_PIN_INPUT},
+ {CPM_PORTA, 11, CPM_PIN_INPUT},
+ {CPM_PORTA, 3, CPM_PIN_INPUT},
+ {CPM_PORTA, 2, CPM_PIN_INPUT},
+ {CPM_PORTC, 13, CPM_PIN_INPUT},
+};
+
+static void __init init_ioports(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mgsuvd_pins); i++) {
+ struct cpm_pin *pin = &mgsuvd_pins[i];
+ cpm1_set_pin(pin->port, pin->pin, pin->flags);
+ }
+
+ setbits16(&mpc8xx_immr->im_ioport.iop_pcso, 0x300);
+ cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK5, CPM_CLK_RX);
+ cpm1_clk_setup(CPM_CLK_SCC3, CPM_CLK6, CPM_CLK_TX);
+ cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX);
+}
+
+static void __init mgsuvd_setup_arch(void)
+{
+ cpm_reset();
+ init_ioports();
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+ { .compatible = "simple-bus" },
+ {},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+ of_platform_bus_probe(NULL, of_bus_ids, NULL);
+ return 0;
+}
+machine_device_initcall(mgsuvd, declare_of_platform_devices);
+
+static int __init mgsuvd_probe(void)
+{
+ unsigned long root = of_get_flat_dt_root();
+ return of_flat_dt_is_compatible(root, "keymile,mgsuvd");
+}
+
+define_machine(mgsuvd) {
+ .name = "MGSUVD",
+ .probe = mgsuvd_probe,
+ .setup_arch = mgsuvd_setup_arch,
+ .init_IRQ = mpc8xx_pics_init,
+ .get_irq = mpc8xx_get_irq,
+ .restart = mpc8xx_restart,
+ .calibrate_decr = mpc8xx_calibrate_decr,
+ .set_rtc_time = mpc8xx_set_rtc_time,
+ .get_rtc_time = mpc8xx_get_rtc_time,
+};
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index 4c900efa164..47e956c871f 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -239,7 +239,8 @@ config TAU_AVERAGE
If in doubt, say N here.
config QUICC_ENGINE
- bool
+ bool "Freescale QUICC Engine (QE) Support"
+ depends on FSL_SOC
select PPC_LIB_RHEAP
select CRC32
help
@@ -248,6 +249,15 @@ config QUICC_ENGINE
Selecting this option means that you wish to build a kernel
for a machine with a QE coprocessor.
+config QE_GPIO
+ bool "QE GPIO support"
+ depends on QUICC_ENGINE
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here if you're going to use hardware that connects to the
+ QE GPIOs.
+
config CPM2
bool "Enable support for the CPM2 (Communications Processor Module)"
depends on MPC85xx || 8260
@@ -293,4 +303,13 @@ config OF_RTC
source "arch/powerpc/sysdev/bestcomm/Kconfig"
+config MPC8xxx_GPIO
+ bool "MPC8xxx GPIO support"
+ depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || PPC_85xx || PPC_86xx
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here if you're going to use hardware that connects to the
+ MPC831x/834x/837x/8572/8610 GPIOs.
+
endmenu
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype
index 7f651273386..439c5ba34ec 100644
--- a/arch/powerpc/platforms/Kconfig.cputype
+++ b/arch/powerpc/platforms/Kconfig.cputype
@@ -50,6 +50,7 @@ config 44x
select PPC_UDBG_16550
select 4xx_SOC
select PPC_PCI_CHOICE
+ select PHYS_64BIT
config E200
bool "Freescale e200"
@@ -128,18 +129,20 @@ config FSL_EMB_PERFMON
config PTE_64BIT
bool
- depends on 44x || E500
- default y if 44x
- default y if E500 && PHYS_64BIT
+ depends on 44x || E500 || PPC_86xx
+ default y if PHYS_64BIT
config PHYS_64BIT
- bool 'Large physical address support' if E500
- depends on 44x || E500
+ bool 'Large physical address support' if E500 || PPC_86xx
+ depends on (44x || E500 || PPC_86xx) && !PPC_83xx && !PPC_82xx
select RESOURCES_64BIT
- default y if 44x
---help---
This option enables kernel support for larger than 32-bit physical
- addresses. This features is not be available on all e500 cores.
+ addresses. This feature may not be available on all cores.
+
+ If you have more than 3.5GB of RAM or so, you also need to enable
+ SWIOTLB under Kernel Options for this to work. The actual number
+ is platform-dependent.
If in doubt, say N here.
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index e06420af5fe..ef92e714621 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -556,11 +556,11 @@ static struct iommu_table *cell_get_iommu_table(struct device *dev)
* node's iommu. We -might- do something smarter later though it may
* never be necessary
*/
- iommu = cell_iommu_for_node(archdata->numa_node);
+ iommu = cell_iommu_for_node(dev_to_node(dev));
if (iommu == NULL || list_empty(&iommu->windows)) {
printk(KERN_ERR "iommu: missing iommu for %s (node %d)\n",
archdata->of_node ? archdata->of_node->full_name : "?",
- archdata->numa_node);
+ dev_to_node(dev));
return NULL;
}
window = list_entry(iommu->windows.next, struct iommu_window, list);
@@ -577,7 +577,7 @@ static void *dma_fixed_alloc_coherent(struct device *dev, size_t size,
return iommu_alloc_coherent(dev, cell_get_iommu_table(dev),
size, dma_handle,
device_to_mask(dev), flag,
- dev->archdata.numa_node);
+ dev_to_node(dev));
else
return dma_direct_ops.alloc_coherent(dev, size, dma_handle,
flag);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 2c8b8091250..cb85d237e49 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -298,8 +298,8 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
d_instantiate(dentry, inode);
dget(dentry);
- dir->i_nlink++;
- dentry->d_inode->i_nlink++;
+ inc_nlink(dir);
+ inc_nlink(dentry->d_inode);
goto out;
out_free_ctx:
@@ -496,6 +496,8 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
ret = spufs_context_open(dget(dentry), mntget(mnt));
if (ret < 0) {
WARN_ON(spufs_rmdir(inode, dentry));
+ if (affinity)
+ mutex_unlock(&gang->aff_mutex);
mutex_unlock(&inode->i_mutex);
spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
goto out;
@@ -538,8 +540,8 @@ spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
inode->i_fop = &simple_dir_operations;
d_instantiate(dentry, inode);
- dir->i_nlink++;
- dentry->d_inode->i_nlink++;
+ inc_nlink(dir);
+ inc_nlink(dentry->d_inode);
return ret;
out_iput:
@@ -755,6 +757,7 @@ spufs_create_root(struct super_block *sb, void *data)
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
SPUFS_I(inode)->i_ctx = NULL;
+ inc_nlink(inode);
ret = -EINVAL;
if (!spufs_parse_options(sb, data, inode))
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c
index 768c262b936..d3cde6b9d2d 100644
--- a/arch/powerpc/platforms/chrp/pci.c
+++ b/arch/powerpc/platforms/chrp/pci.c
@@ -260,13 +260,13 @@ chrp_find_bridges(void)
dev->full_name);
continue;
}
- hose->first_busno = bus_range[0];
+ hose->first_busno = hose->self_busno = bus_range[0];
hose->last_busno = bus_range[1];
model = of_get_property(dev, "model", NULL);
if (model == NULL)
model = "<none>";
- if (of_device_is_compatible(dev, "IBM,python")) {
+ if (strncmp(model, "IBM, Python", 11) == 0) {
setup_python(hose, dev);
} else if (is_mot
|| strncmp(model, "Motorola, Grackle", 17) == 0) {
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 96d1e4b3c49..054dfe5b8e7 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -94,12 +94,12 @@ int chrp_set_rtc_time(struct rtc_time *tmarg)
chrp_cmos_clock_write((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- 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);
+ tm.tm_sec = bin2bcd(tm.tm_sec);
+ tm.tm_min = bin2bcd(tm.tm_min);
+ tm.tm_hour = bin2bcd(tm.tm_hour);
+ tm.tm_mon = bin2bcd(tm.tm_mon);
+ tm.tm_mday = bin2bcd(tm.tm_mday);
+ tm.tm_year = bin2bcd(tm.tm_year);
}
chrp_cmos_clock_write(tm.tm_sec,RTC_SECONDS);
chrp_cmos_clock_write(tm.tm_min,RTC_MINUTES);
@@ -136,12 +136,12 @@ void chrp_get_rtc_time(struct rtc_time *tm)
} while (sec != chrp_cmos_clock_read(RTC_SECONDS));
if (!(chrp_cmos_clock_read(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- 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 = bcd2bin(sec);
+ min = bcd2bin(min);
+ hour = bcd2bin(hour);
+ day = bcd2bin(day);
+ mon = bcd2bin(mon);
+ year = bcd2bin(year);
}
if (year < 70)
year += 100;
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index 84e2d78b9a6..7a2ba39d781 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -164,7 +164,6 @@ static void __init mpc7448_hpc2_init_IRQ(void)
void mpc7448_hpc2_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "vendor\t\t: Freescale Semiconductor\n");
- seq_printf(m, "machine\t\t: MPC7448hpc2\n");
}
void mpc7448_hpc2_restart(char *cmd)
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S
index 8ff330d026c..2f581521eb9 100644
--- a/arch/powerpc/platforms/iseries/exception.S
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -38,12 +38,13 @@
.globl system_reset_iSeries
system_reset_iSeries:
+ bl .relative_toc
mfspr r13,SPRN_SPRG3 /* Get alpaca address */
- LOAD_REG_IMMEDIATE(r23, alpaca)
+ LOAD_REG_ADDR(r23, alpaca)
li r0,ALPACA_SIZE
sub r23,r13,r23
divdu r23,r23,r0 /* r23 has cpu number */
- LOAD_REG_IMMEDIATE(r13, paca)
+ LOAD_REG_ADDR(r13, paca)
mulli r0,r23,PACA_SIZE
add r13,r13,r0
mtspr SPRN_SPRG3,r13 /* Save it away for the future */
@@ -60,14 +61,14 @@ system_reset_iSeries:
mtspr SPRN_CTRLT,r4
/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */
-/* In the UP case we'll yeild() later, and we will not access the paca anyway */
+/* In the UP case we'll yield() later, and we will not access the paca anyway */
#ifdef CONFIG_SMP
1:
HMT_LOW
- LOAD_REG_IMMEDIATE(r23, __secondary_hold_spinloop)
+ LOAD_REG_ADDR(r23, __secondary_hold_spinloop)
ld r23,0(r23)
sync
- LOAD_REG_IMMEDIATE(r3,current_set)
+ LOAD_REG_ADDR(r3,current_set)
sldi r28,r24,3 /* get current_set[cpu#] */
ldx r3,r3,r28
addi r1,r3,THREAD_SIZE
@@ -90,7 +91,7 @@ system_reset_iSeries:
lbz r23,PACAPROCSTART(r13) /* Test if this processor
* should start */
sync
- LOAD_REG_IMMEDIATE(r3,current_set)
+ LOAD_REG_ADDR(r3,current_set)
sldi r28,r24,3 /* get current_set[cpu#] */
ldx r3,r3,r28
addi r1,r3,THREAD_SIZE
@@ -255,8 +256,8 @@ hardware_interrupt_iSeries_masked:
_INIT_STATIC(__start_initialization_iSeries)
/* Clear out the BSS */
- LOAD_REG_IMMEDIATE(r11,__bss_stop)
- LOAD_REG_IMMEDIATE(r8,__bss_start)
+ LOAD_REG_ADDR(r11,__bss_stop)
+ LOAD_REG_ADDR(r8,__bss_start)
sub r11,r11,r8 /* bss size */
addi r11,r11,7 /* round up to an even double word */
rldicl. r11,r11,61,3 /* shift right by 3 */
@@ -267,15 +268,11 @@ _INIT_STATIC(__start_initialization_iSeries)
3: stdu r0,8(r8)
bdnz 3b
4:
- LOAD_REG_IMMEDIATE(r1,init_thread_union)
+ LOAD_REG_ADDR(r1,init_thread_union)
addi r1,r1,THREAD_SIZE
li r0,0
stdu r0,-STACK_FRAME_OVERHEAD(r1)
- LOAD_REG_IMMEDIATE(r2,__toc_start)
- addi r2,r2,0x4000
- addi r2,r2,0x4000
-
bl .iSeries_early_setup
bl .early_setup
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index 731d7b15774..3689c2413d2 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -722,13 +722,13 @@ static int mf_set_rtc(struct rtc_time *tm)
day = tm->tm_mday;
mon = tm->tm_mon + 1;
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hour);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(day);
- BIN_TO_BCD(y1);
- BIN_TO_BCD(y2);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hour = bin2bcd(hour);
+ mon = bin2bcd(mon);
+ day = bin2bcd(day);
+ y1 = bin2bcd(y1);
+ y2 = bin2bcd(y2);
memset(ce_time, 0, sizeof(ce_time));
ce_time[3] = 0x41;
@@ -777,12 +777,12 @@ static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
u8 day = ce_msg[10];
u8 mon = ce_msg[11];
- 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 = bcd2bin(sec);
+ min = bcd2bin(min);
+ hour = bcd2bin(hour);
+ day = bcd2bin(day);
+ mon = bcd2bin(mon);
+ year = bcd2bin(year);
if (year <= 69)
year += 100;
diff --git a/arch/powerpc/platforms/maple/time.c b/arch/powerpc/platforms/maple/time.c
index 53bca132fb4..eac569dee27 100644
--- a/arch/powerpc/platforms/maple/time.c
+++ b/arch/powerpc/platforms/maple/time.c
@@ -68,12 +68,12 @@ void maple_get_rtc_time(struct rtc_time *tm)
if (!(maple_clock_read(RTC_CONTROL) & RTC_DM_BINARY)
|| RTC_ALWAYS_BCD) {
- BCD_TO_BIN(tm->tm_sec);
- BCD_TO_BIN(tm->tm_min);
- BCD_TO_BIN(tm->tm_hour);
- BCD_TO_BIN(tm->tm_mday);
- BCD_TO_BIN(tm->tm_mon);
- BCD_TO_BIN(tm->tm_year);
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon);
+ tm->tm_year = bcd2bin(tm->tm_year);
}
if ((tm->tm_year + 1900) < 1970)
tm->tm_year += 100;
@@ -104,12 +104,12 @@ int maple_set_rtc_time(struct rtc_time *tm)
year = tm->tm_year;
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
- BIN_TO_BCD(sec);
- BIN_TO_BCD(min);
- BIN_TO_BCD(hour);
- BIN_TO_BCD(mon);
- BIN_TO_BCD(mday);
- BIN_TO_BCD(year);
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hour = bin2bcd(hour);
+ mon = bin2bcd(mon);
+ mday = bin2bcd(mday);
+ year = bin2bcd(year);
}
maple_clock_write(sec, RTC_SECONDS);
maple_clock_write(min, RTC_MINUTES);
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index 5169ecc3712..e6c0040ee79 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -2677,7 +2677,7 @@ static void __init probe_one_macio(const char *name, const char *compat, int typ
macio_chips[i].of_node = node;
macio_chips[i].type = type;
macio_chips[i].base = base;
- macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON;
+ macio_chips[i].flags = MACIO_FLAG_SCCA_ON | MACIO_FLAG_SCCB_ON;
macio_chips[i].name = macio_names[type];
revp = of_get_property(node, "revision-id", NULL);
if (revp)
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 4ae3d00e0bd..40f72c2a469 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -787,7 +787,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
{
unsigned int save_vector;
unsigned long target, flags;
- unsigned int *vector = (unsigned int *)(KERNELBASE+0x100);
+ unsigned int *vector = (unsigned int *)(PAGE_OFFSET+0x100);
if (nr < 0 || nr > 3)
return;
@@ -801,7 +801,7 @@ static void __devinit smp_core99_kick_cpu(int nr)
save_vector = *vector;
/* Setup fake reset vector that does
- * b __secondary_start_pmac_0 + nr*8 - KERNELBASE
+ * b __secondary_start_pmac_0 + nr*8
*/
target = (unsigned long) __secondary_start_pmac_0 + nr * 8;
patch_branch(vector, target, BRANCH_SET_LINK);
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index bbbefd64ab5..59eb840d8ce 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -93,11 +93,14 @@ static void to_rtc_time(unsigned long now, struct rtc_time *tm)
}
#endif
+#if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) || \
+ defined(CONFIG_PMAC_SMU)
static unsigned long from_rtc_time(struct rtc_time *tm)
{
return mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
}
+#endif
#ifdef CONFIG_ADB_CUDA
static unsigned long cuda_get_time(void)
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
index 280ee88cb0b..a789bf58ca8 100644
--- a/arch/powerpc/platforms/ps3/system-bus.c
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -762,7 +762,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
};
dev->core.archdata.of_node = NULL;
- dev->core.archdata.numa_node = 0;
+ set_dev_node(&dev->core, 0);
pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c
index 38fe32a7cc7..5cd4d276162 100644
--- a/arch/powerpc/platforms/pseries/cmm.c
+++ b/arch/powerpc/platforms/pseries/cmm.c
@@ -121,7 +121,7 @@ static long cmm_alloc_pages(long nr)
npa = (struct cmm_page_array *)__get_free_page(GFP_NOIO | __GFP_NOWARN |
__GFP_NORETRY | __GFP_NOMEMALLOC);
if (!npa) {
- pr_info("%s: Can not allocate new page list\n", __FUNCTION__);
+ pr_info("%s: Can not allocate new page list\n", __func__);
free_page(addr);
break;
}
@@ -138,7 +138,7 @@ static long cmm_alloc_pages(long nr)
}
if ((rc = plpar_page_set_loaned(__pa(addr)))) {
- pr_err("%s: Can not set page to loaned. rc=%ld\n", __FUNCTION__, rc);
+ pr_err("%s: Can not set page to loaned. rc=%ld\n", __func__, rc);
spin_unlock(&cmm_lock);
free_page(addr);
break;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index 8c1ca477c52..0ad56ff7b4a 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -41,7 +41,7 @@ static inline const char * pcid_name (struct pci_dev *pdev)
return "";
}
-#ifdef DEBUG
+#if 0
static void print_device_node_tree(struct pci_dn *pdn, int dent)
{
int i;
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index a1a368dd2d9..140d02a5232 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -21,7 +21,7 @@ static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size)
struct zone *zone;
int ret;
- start_pfn = base >> PFN_SECTION_SHIFT;
+ start_pfn = base >> PAGE_SHIFT;
zone = page_zone(pfn_to_page(start_pfn));
/*
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 7637bd38c79..c591a25b0b0 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -466,11 +466,11 @@ static int do_update_property(char *buf, size_t bufsize)
else
action = PSERIES_DRCONF_MEM_REMOVE;
- blocking_notifier_call_chain(&pSeries_reconfig_chain,
- action, value);
+ rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
+ action, value);
}
- return 0;
+ return rc;
}
/**
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index c9ffd8c225f..f4e55be2eea 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -295,19 +295,29 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf,
if (!tmp)
return -ENOMEM;
-
spin_lock_irqsave(&rtasd_log_lock, s);
/* if it's 0, then we know we got the last one (the one in NVRAM) */
- if (rtas_log_size == 0 && logging_enabled)
- nvram_clear_error_log();
- spin_unlock_irqrestore(&rtasd_log_lock, s);
+ while (rtas_log_size == 0) {
+ if (file->f_flags & O_NONBLOCK) {
+ spin_unlock_irqrestore(&rtasd_log_lock, s);
+ error = -EAGAIN;
+ goto out;
+ }
+ if (!logging_enabled) {
+ spin_unlock_irqrestore(&rtasd_log_lock, s);
+ error = -ENODATA;
+ goto out;
+ }
+ nvram_clear_error_log();
- error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
- if (error)
- goto out;
+ spin_unlock_irqrestore(&rtasd_log_lock, s);
+ error = wait_event_interruptible(rtas_log_wait, rtas_log_size);
+ if (error)
+ goto out;
+ spin_lock_irqsave(&rtasd_log_lock, s);
+ }
- spin_lock_irqsave(&rtasd_log_lock, s);
offset = rtas_error_log_buffer_max * (rtas_log_start & LOG_NUMBER_MASK);
memcpy(tmp, &rtas_log_buf[offset], count);
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c
index 9d8f8c84ab8..e00f96baa38 100644
--- a/arch/powerpc/platforms/pseries/smp.c
+++ b/arch/powerpc/platforms/pseries/smp.c
@@ -37,7 +37,6 @@
#include <asm/paca.h>
#include <asm/time.h>
#include <asm/machdep.h>
-#include "xics.h"
#include <asm/cputable.h>
#include <asm/firmware.h>
#include <asm/system.h>
@@ -49,6 +48,7 @@
#include "plpar_wrappers.h"
#include "pseries.h"
+#include "xics.h"
/*
@@ -105,36 +105,6 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu)
}
#ifdef CONFIG_XICS
-static inline void smp_xics_do_message(int cpu, int msg)
-{
- set_bit(msg, &xics_ipi_message[cpu].value);
- mb();
- xics_cause_IPI(cpu);
-}
-
-static void smp_xics_message_pass(int target, int msg)
-{
- unsigned int i;
-
- if (target < NR_CPUS) {
- smp_xics_do_message(target, msg);
- } else {
- for_each_online_cpu(i) {
- if (target == MSG_ALL_BUT_SELF
- && i == smp_processor_id())
- continue;
- smp_xics_do_message(i, msg);
- }
- }
-}
-
-static int __init smp_xics_probe(void)
-{
- xics_request_IPIs();
-
- return cpus_weight(cpu_possible_map);
-}
-
static void __devinit smp_xics_setup_cpu(int cpu)
{
if (cpu != boot_cpuid)
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 0fc830f576f..e1904774a70 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -9,32 +9,30 @@
* 2 of the License, or (at your option) any later version.
*/
-
#include <linux/types.h>
#include <linux/threads.h>
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/smp.h>
#include <linux/interrupt.h>
-#include <linux/signal.h>
#include <linux/init.h>
-#include <linux/gfp.h>
#include <linux/radix-tree.h>
#include <linux/cpu.h>
+#include <linux/of.h>
#include <asm/firmware.h>
-#include <asm/prom.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/smp.h>
#include <asm/rtas.h>
#include <asm/hvcall.h>
#include <asm/machdep.h>
-#include <asm/i8259.h>
#include "xics.h"
#include "plpar_wrappers.h"
+static struct irq_host *xics_host;
+
#define XICS_IPI 2
#define XICS_IRQ_SPURIOUS 0
@@ -47,6 +45,20 @@
*/
#define IPI_PRIORITY 4
+static unsigned int default_server = 0xFF;
+static unsigned int default_distrib_server = 0;
+static unsigned int interrupt_server_size = 8;
+
+/* RTAS service tokens */
+static int ibm_get_xive;
+static int ibm_set_xive;
+static int ibm_int_on;
+static int ibm_int_off;
+
+
+/* Direct hardware low level accessors */
+
+/* The part of the interrupt presentation layer that we care about */
struct xics_ipl {
union {
u32 word;
@@ -65,27 +77,6 @@ struct xics_ipl {
static struct xics_ipl __iomem *xics_per_cpu[NR_CPUS];
-static unsigned int default_server = 0xFF;
-static unsigned int default_distrib_server = 0;
-static unsigned int interrupt_server_size = 8;
-
-static struct irq_host *xics_host;
-
-/*
- * XICS only has a single IPI, so encode the messages per CPU
- */
-struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
-
-/* RTAS service tokens */
-static int ibm_get_xive;
-static int ibm_set_xive;
-static int ibm_int_on;
-static int ibm_int_off;
-
-
-/* Direct HW low level accessors */
-
-
static inline unsigned int direct_xirr_info_get(void)
{
int cpu = smp_processor_id();
@@ -93,7 +84,7 @@ static inline unsigned int direct_xirr_info_get(void)
return in_be32(&xics_per_cpu[cpu]->xirr.word);
}
-static inline void direct_xirr_info_set(int value)
+static inline void direct_xirr_info_set(unsigned int value)
{
int cpu = smp_processor_id();
@@ -115,7 +106,6 @@ static inline void direct_qirr_info(int n_cpu, u8 value)
/* LPAR low level accessors */
-
static inline unsigned int lpar_xirr_info_get(void)
{
unsigned long lpar_rc;
@@ -127,15 +117,14 @@ static inline unsigned int lpar_xirr_info_get(void)
return (unsigned int)return_value;
}
-static inline void lpar_xirr_info_set(int value)
+static inline void lpar_xirr_info_set(unsigned int value)
{
unsigned long lpar_rc;
- unsigned long val64 = value & 0xffffffff;
- lpar_rc = plpar_eoi(val64);
+ lpar_rc = plpar_eoi(value);
if (lpar_rc != H_SUCCESS)
- panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc,
- val64);
+ panic("bad return code EOI - rc = %ld, value=%x\n", lpar_rc,
+ value);
}
static inline void lpar_cppr_info(u8 value)
@@ -157,48 +146,7 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
}
-/* High level handlers and init code */
-
-static void xics_update_irq_servers(void)
-{
- int i, j;
- struct device_node *np;
- u32 ilen;
- const u32 *ireg, *isize;
- u32 hcpuid;
-
- /* Find the server numbers for the boot cpu. */
- np = of_get_cpu_node(boot_cpuid, NULL);
- BUG_ON(!np);
-
- ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
- if (!ireg) {
- of_node_put(np);
- return;
- }
-
- i = ilen / sizeof(int);
- hcpuid = get_hard_smp_processor_id(boot_cpuid);
-
- /* Global interrupt distribution server is specified in the last
- * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
- * entry fom this property for current boot cpu id and use it as
- * default distribution server
- */
- for (j = 0; j < i; j += 2) {
- if (ireg[j] == hcpuid) {
- default_server = hcpuid;
- default_distrib_server = ireg[j+1];
-
- isize = of_get_property(np,
- "ibm,interrupt-server#-size", NULL);
- if (isize)
- interrupt_server_size = *isize;
- }
- }
-
- of_node_put(np);
-}
+/* Interface to generic irq subsystem */
#ifdef CONFIG_SMP
static int get_irq_server(unsigned int virq, unsigned int strict_check)
@@ -208,9 +156,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
cpumask_t cpumask = irq_desc[virq].affinity;
cpumask_t tmp = CPU_MASK_NONE;
- if (! cpu_isset(default_server, cpu_online_map))
- xics_update_irq_servers();
-
if (!distribute_irqs)
return default_server;
@@ -238,7 +183,6 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
}
#endif
-
static void xics_unmask_irq(unsigned int virq)
{
unsigned int irq;
@@ -257,21 +201,28 @@ static void xics_unmask_irq(unsigned int virq)
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
DEFAULT_PRIORITY);
if (call_status != 0) {
- printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_set_xive "
- "returned %d\n", irq, call_status);
- printk("set_xive %x, server %x\n", ibm_set_xive, server);
+ printk(KERN_ERR
+ "%s: ibm_set_xive irq %u server %x returned %d\n",
+ __func__, irq, server, call_status);
return;
}
/* Now unmask the interrupt (often a no-op) */
call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
if (call_status != 0) {
- printk(KERN_ERR "xics_enable_irq: irq=%u: ibm_int_on "
- "returned %d\n", irq, call_status);
+ printk(KERN_ERR "%s: ibm_int_on irq=%u returned %d\n",
+ __func__, irq, call_status);
return;
}
}
+static unsigned int xics_startup(unsigned int virq)
+{
+ /* unmask it */
+ xics_unmask_irq(virq);
+ return 0;
+}
+
static void xics_mask_real_irq(unsigned int irq)
{
int call_status;
@@ -281,8 +232,8 @@ static void xics_mask_real_irq(unsigned int irq)
call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
if (call_status != 0) {
- printk(KERN_ERR "xics_disable_real_irq: irq=%u: "
- "ibm_int_off returned %d\n", irq, call_status);
+ printk(KERN_ERR "%s: ibm_int_off irq=%u returned %d\n",
+ __func__, irq, call_status);
return;
}
@@ -290,8 +241,8 @@ static void xics_mask_real_irq(unsigned int irq)
call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq,
default_server, 0xff);
if (call_status != 0) {
- printk(KERN_ERR "xics_disable_irq: irq=%u: ibm_set_xive(0xff)"
- " returned %d\n", irq, call_status);
+ printk(KERN_ERR "%s: ibm_set_xive(0xff) irq=%u returned %d\n",
+ __func__, irq, call_status);
return;
}
}
@@ -308,132 +259,77 @@ static void xics_mask_irq(unsigned int virq)
xics_mask_real_irq(irq);
}
-static unsigned int xics_startup(unsigned int virq)
-{
- unsigned int irq;
-
- /* force a reverse mapping of the interrupt so it gets in the cache */
- irq = (unsigned int)irq_map[virq].hwirq;
- irq_radix_revmap(xics_host, irq);
-
- /* unmask it */
- xics_unmask_irq(virq);
- return 0;
-}
-
-static void xics_eoi_direct(unsigned int virq)
+static void xics_mask_unknown_vec(unsigned int vec)
{
- unsigned int irq = (unsigned int)irq_map[virq].hwirq;
-
- iosync();
- direct_xirr_info_set((0xff << 24) | irq);
+ printk(KERN_ERR "Interrupt %u (real) is invalid, disabling it.\n", vec);
+ xics_mask_real_irq(vec);
}
-
-static void xics_eoi_lpar(unsigned int virq)
+static inline unsigned int xics_xirr_vector(unsigned int xirr)
{
- unsigned int irq = (unsigned int)irq_map[virq].hwirq;
-
- iosync();
- lpar_xirr_info_set((0xff << 24) | irq);
+ /*
+ * The top byte is the old cppr, to be restored on EOI.
+ * The remaining 24 bits are the vector.
+ */
+ return xirr & 0x00ffffff;
}
-static inline unsigned int xics_remap_irq(unsigned int vec)
+static unsigned int xics_get_irq_direct(void)
{
+ unsigned int xirr = direct_xirr_info_get();
+ unsigned int vec = xics_xirr_vector(xirr);
unsigned int irq;
- vec &= 0x00ffffff;
-
if (vec == XICS_IRQ_SPURIOUS)
return NO_IRQ;
- irq = irq_radix_revmap(xics_host, vec);
+
+ irq = irq_radix_revmap_lookup(xics_host, vec);
if (likely(irq != NO_IRQ))
return irq;
- printk(KERN_ERR "Interrupt %u (real) is invalid,"
- " disabling it.\n", vec);
- xics_mask_real_irq(vec);
- return NO_IRQ;
-}
+ /* We don't have a linux mapping, so have rtas mask it. */
+ xics_mask_unknown_vec(vec);
-static unsigned int xics_get_irq_direct(void)
-{
- return xics_remap_irq(direct_xirr_info_get());
+ /* We might learn about it later, so EOI it */
+ direct_xirr_info_set(xirr);
+ return NO_IRQ;
}
static unsigned int xics_get_irq_lpar(void)
{
- return xics_remap_irq(lpar_xirr_info_get());
-}
-
-#ifdef CONFIG_SMP
-
-static irqreturn_t xics_ipi_dispatch(int cpu)
-{
- WARN_ON(cpu_is_offline(cpu));
+ unsigned int xirr = lpar_xirr_info_get();
+ unsigned int vec = xics_xirr_vector(xirr);
+ unsigned int irq;
- while (xics_ipi_message[cpu].value) {
- if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
- &xics_ipi_message[cpu].value)) {
- mb();
- smp_message_recv(PPC_MSG_CALL_FUNCTION);
- }
- if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
- &xics_ipi_message[cpu].value)) {
- mb();
- smp_message_recv(PPC_MSG_RESCHEDULE);
- }
- if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
- &xics_ipi_message[cpu].value)) {
- mb();
- smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
- }
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
- if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
- &xics_ipi_message[cpu].value)) {
- mb();
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
- }
-#endif
- }
- return IRQ_HANDLED;
-}
+ if (vec == XICS_IRQ_SPURIOUS)
+ return NO_IRQ;
-static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
-{
- int cpu = smp_processor_id();
+ irq = irq_radix_revmap_lookup(xics_host, vec);
+ if (likely(irq != NO_IRQ))
+ return irq;
- direct_qirr_info(cpu, 0xff);
+ /* We don't have a linux mapping, so have RTAS mask it. */
+ xics_mask_unknown_vec(vec);
- return xics_ipi_dispatch(cpu);
+ /* We might learn about it later, so EOI it */
+ lpar_xirr_info_set(xirr);
+ return NO_IRQ;
}
-static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
+static void xics_eoi_direct(unsigned int virq)
{
- int cpu = smp_processor_id();
-
- lpar_qirr_info(cpu, 0xff);
+ unsigned int irq = (unsigned int)irq_map[virq].hwirq;
- return xics_ipi_dispatch(cpu);
+ iosync();
+ direct_xirr_info_set((0xff << 24) | irq);
}
-void xics_cause_IPI(int cpu)
+static void xics_eoi_lpar(unsigned int virq)
{
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_qirr_info(cpu, IPI_PRIORITY);
- else
- direct_qirr_info(cpu, IPI_PRIORITY);
-}
-
-#endif /* CONFIG_SMP */
+ unsigned int irq = (unsigned int)irq_map[virq].hwirq;
-static void xics_set_cpu_priority(unsigned char cppr)
-{
- if (firmware_has_feature(FW_FEATURE_LPAR))
- lpar_cppr_info(cppr);
- else
- direct_cppr_info(cppr);
iosync();
+ lpar_xirr_info_set((0xff << 24) | irq);
}
static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
@@ -450,8 +346,8 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
if (status) {
- printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive "
- "returns %d\n", irq, status);
+ printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
+ __func__, irq, status);
return;
}
@@ -463,8 +359,9 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
if (irq_server == -1) {
char cpulist[128];
cpumask_scnprintf(cpulist, sizeof(cpulist), cpumask);
- printk(KERN_WARNING "xics_set_affinity: No online cpus in "
- "the mask %s for irq %d\n", cpulist, virq);
+ printk(KERN_WARNING
+ "%s: No online cpus in the mask %s for irq %d\n",
+ __func__, cpulist, virq);
return;
}
@@ -472,28 +369,12 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
irq, irq_server, xics_status[1]);
if (status) {
- printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive "
- "returns %d\n", irq, status);
+ printk(KERN_ERR "%s: ibm,set-xive irq=%u returns %d\n",
+ __func__, irq, status);
return;
}
}
-void xics_setup_cpu(void)
-{
- xics_set_cpu_priority(0xff);
-
- /*
- * Put the calling processor into the GIQ. This is really only
- * necessary from a secondary thread as the OF start-cpu interface
- * performs this function for us on primary threads.
- *
- * XXX: undo of teardown on kexec needs this too, as may hotplug
- */
- rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
- (1UL << interrupt_server_size) - 1 - default_distrib_server, 1);
-}
-
-
static struct irq_chip xics_pic_direct = {
.typename = " XICS ",
.startup = xics_startup,
@@ -503,7 +384,6 @@ static struct irq_chip xics_pic_direct = {
.set_affinity = xics_set_affinity
};
-
static struct irq_chip xics_pic_lpar = {
.typename = " XICS ",
.startup = xics_startup,
@@ -513,6 +393,9 @@ static struct irq_chip xics_pic_lpar = {
.set_affinity = xics_set_affinity
};
+
+/* Interface to arch irq controller subsystem layer */
+
/* Points to the irq_chip we're actually using */
static struct irq_chip *xics_irq_chip;
@@ -530,6 +413,9 @@ static int xics_host_map(struct irq_host *h, unsigned int virq,
{
pr_debug("xics: map virq %d, hwirq 0x%lx\n", virq, hw);
+ /* Insert the interrupt mapping into the radix tree for fast lookup */
+ irq_radix_revmap_insert(xics_host, virq, hw);
+
get_irq_desc(virq)->status |= IRQ_LEVEL;
set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq);
return 0;
@@ -569,10 +455,169 @@ static void __init xics_init_host(void)
irq_set_default_host(xics_host);
}
+
+/* Inter-processor interrupt support */
+
+#ifdef CONFIG_SMP
+/*
+ * XICS only has a single IPI, so encode the messages per CPU
+ */
+struct xics_ipi_struct {
+ unsigned long value;
+ } ____cacheline_aligned;
+
+static struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+
+static inline void smp_xics_do_message(int cpu, int msg)
+{
+ set_bit(msg, &xics_ipi_message[cpu].value);
+ mb();
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ lpar_qirr_info(cpu, IPI_PRIORITY);
+ else
+ direct_qirr_info(cpu, IPI_PRIORITY);
+}
+
+void smp_xics_message_pass(int target, int msg)
+{
+ unsigned int i;
+
+ if (target < NR_CPUS) {
+ smp_xics_do_message(target, msg);
+ } else {
+ for_each_online_cpu(i) {
+ if (target == MSG_ALL_BUT_SELF
+ && i == smp_processor_id())
+ continue;
+ smp_xics_do_message(i, msg);
+ }
+ }
+}
+
+static irqreturn_t xics_ipi_dispatch(int cpu)
+{
+ WARN_ON(cpu_is_offline(cpu));
+
+ mb(); /* order mmio clearing qirr */
+ while (xics_ipi_message[cpu].value) {
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
+ &xics_ipi_message[cpu].value)) {
+ smp_message_recv(PPC_MSG_CALL_FUNCTION);
+ }
+ if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
+ &xics_ipi_message[cpu].value)) {
+ smp_message_recv(PPC_MSG_RESCHEDULE);
+ }
+ if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE,
+ &xics_ipi_message[cpu].value)) {
+ smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
+ }
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+ if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
+ &xics_ipi_message[cpu].value)) {
+ smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+ }
+#endif
+ }
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
+{
+ int cpu = smp_processor_id();
+
+ direct_qirr_info(cpu, 0xff);
+
+ return xics_ipi_dispatch(cpu);
+}
+
+static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
+{
+ int cpu = smp_processor_id();
+
+ lpar_qirr_info(cpu, 0xff);
+
+ return xics_ipi_dispatch(cpu);
+}
+
+static void xics_request_ipi(void)
+{
+ unsigned int ipi;
+ int rc;
+
+ ipi = irq_create_mapping(xics_host, XICS_IPI);
+ BUG_ON(ipi == NO_IRQ);
+
+ /*
+ * IPIs are marked IRQF_DISABLED as they must run with irqs
+ * disabled
+ */
+ set_irq_handler(ipi, handle_percpu_irq);
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ rc = request_irq(ipi, xics_ipi_action_lpar,
+ IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+ else
+ rc = request_irq(ipi, xics_ipi_action_direct,
+ IRQF_DISABLED|IRQF_PERCPU, "IPI", NULL);
+ BUG_ON(rc);
+}
+
+int __init smp_xics_probe(void)
+{
+ xics_request_ipi();
+
+ return cpus_weight(cpu_possible_map);
+}
+
+#endif /* CONFIG_SMP */
+
+
+/* Initialization */
+
+static void xics_update_irq_servers(void)
+{
+ int i, j;
+ struct device_node *np;
+ u32 ilen;
+ const u32 *ireg, *isize;
+ u32 hcpuid;
+
+ /* Find the server numbers for the boot cpu. */
+ np = of_get_cpu_node(boot_cpuid, NULL);
+ BUG_ON(!np);
+
+ ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
+ if (!ireg) {
+ of_node_put(np);
+ return;
+ }
+
+ i = ilen / sizeof(int);
+ hcpuid = get_hard_smp_processor_id(boot_cpuid);
+
+ /* Global interrupt distribution server is specified in the last
+ * entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
+ * entry fom this property for current boot cpu id and use it as
+ * default distribution server
+ */
+ for (j = 0; j < i; j += 2) {
+ if (ireg[j] == hcpuid) {
+ default_server = hcpuid;
+ default_distrib_server = ireg[j+1];
+ }
+ }
+
+ /* get the bit size of server numbers */
+ isize = of_get_property(np, "ibm,interrupt-server#-size", NULL);
+ if (isize)
+ interrupt_server_size = *isize;
+
+ of_node_put(np);
+}
+
static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
unsigned long size)
{
-#ifdef CONFIG_SMP
int i;
/* This may look gross but it's good enough for now, we don't quite
@@ -586,11 +631,6 @@ static void __init xics_map_one_cpu(int hw_id, unsigned long addr,
return;
}
}
-#else
- if (hw_id != 0)
- return;
- xics_per_cpu[0] = ioremap(addr, size);
-#endif /* CONFIG_SMP */
}
static void __init xics_init_one_node(struct device_node *np,
@@ -652,15 +692,17 @@ void __init xics_init_IRQ(void)
for_each_node_by_type(np, "PowerPC-External-Interrupt-Presentation") {
found = 1;
- if (firmware_has_feature(FW_FEATURE_LPAR))
+ if (firmware_has_feature(FW_FEATURE_LPAR)) {
+ of_node_put(np);
break;
+ }
xics_init_one_node(np, &indx);
}
if (found == 0)
return;
- xics_init_host();
xics_update_irq_servers();
+ xics_init_host();
if (firmware_has_feature(FW_FEATURE_LPAR))
ppc_md.get_irq = xics_get_irq_lpar;
@@ -672,30 +714,31 @@ void __init xics_init_IRQ(void)
ppc64_boot_msg(0x21, "XICS Done");
}
+/* Cpu startup, shutdown, and hotplug */
-#ifdef CONFIG_SMP
-void xics_request_IPIs(void)
+static void xics_set_cpu_priority(unsigned char cppr)
{
- unsigned int ipi;
- int rc;
-
- ipi = irq_create_mapping(xics_host, XICS_IPI);
- BUG_ON(ipi == NO_IRQ);
-
- /*
- * IPIs are marked IRQF_DISABLED as they must run with irqs
- * disabled
- */
- set_irq_handler(ipi, handle_percpu_irq);
if (firmware_has_feature(FW_FEATURE_LPAR))
- rc = request_irq(ipi, xics_ipi_action_lpar, IRQF_DISABLED,
- "IPI", NULL);
+ lpar_cppr_info(cppr);
else
- rc = request_irq(ipi, xics_ipi_action_direct, IRQF_DISABLED,
- "IPI", NULL);
- BUG_ON(rc);
+ direct_cppr_info(cppr);
+ iosync();
+}
+
+/* Have the calling processor join or leave the specified global queue */
+static void xics_set_cpu_giq(unsigned int gserver, unsigned int join)
+{
+ int status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
+ (1UL << interrupt_server_size) - 1 - gserver, join);
+ WARN_ON(status < 0);
+}
+
+void xics_setup_cpu(void)
+{
+ xics_set_cpu_priority(0xff);
+
+ xics_set_cpu_giq(default_distrib_server, 1);
}
-#endif /* CONFIG_SMP */
void xics_teardown_cpu(void)
{
@@ -703,9 +746,7 @@ void xics_teardown_cpu(void)
xics_set_cpu_priority(0);
- /*
- * Clear IPI
- */
+ /* Clear any pending IPI request */
if (firmware_has_feature(FW_FEATURE_LPAR))
lpar_qirr_info(cpu, 0xff);
else
@@ -714,34 +755,28 @@ void xics_teardown_cpu(void)
void xics_kexec_teardown_cpu(int secondary)
{
- unsigned int ipi;
- struct irq_desc *desc;
-
xics_teardown_cpu();
/*
- * we need to EOI the IPI
+ * we take the ipi irq but and never return so we
+ * need to EOI the IPI, but want to leave our priority 0
*
- * probably need to check all the other interrupts too
+ * should we check all the other interrupts too?
* should we be flagging idle loop instead?
* or creating some task to be scheduled?
*/
- ipi = irq_find_mapping(xics_host, XICS_IPI);
- if (ipi == XICS_IRQ_SPURIOUS)
- return;
- desc = get_irq_desc(ipi);
- if (desc->chip && desc->chip->eoi)
- desc->chip->eoi(ipi);
+ if (firmware_has_feature(FW_FEATURE_LPAR))
+ lpar_xirr_info_set((0x00 << 24) | XICS_IPI);
+ else
+ direct_xirr_info_set((0x00 << 24) | XICS_IPI);
/*
* Some machines need to have at least one cpu in the GIQ,
* so leave the master cpu in the group.
*/
if (secondary)
- rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
- (1UL << interrupt_server_size) - 1 -
- default_distrib_server, 0);
+ xics_set_cpu_giq(default_distrib_server, 0);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -749,17 +784,18 @@ void xics_kexec_teardown_cpu(int secondary)
/* Interrupts are disabled. */
void xics_migrate_irqs_away(void)
{
- int status;
int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id();
unsigned int irq, virq;
+ /* If we used to be the default server, move to the new "boot_cpuid" */
+ if (hw_cpu == default_server)
+ xics_update_irq_servers();
+
/* Reject any interrupt that was queued to us... */
xics_set_cpu_priority(0);
- /* remove ourselves from the global interrupt queue */
- status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE,
- (1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
- WARN_ON(status < 0);
+ /* Remove ourselves from the global interrupt queue */
+ xics_set_cpu_giq(default_distrib_server, 0);
/* Allow IPIs again... */
xics_set_cpu_priority(DEFAULT_PRIORITY);
@@ -767,6 +803,7 @@ void xics_migrate_irqs_away(void)
for_each_irq(virq) {
struct irq_desc *desc;
int xics_status[2];
+ int status;
unsigned long flags;
/* We cant set affinity on ISA interrupts */
@@ -790,9 +827,8 @@ void xics_migrate_irqs_away(void)
status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq);
if (status) {
- printk(KERN_ERR "migrate_irqs_away: irq=%u "
- "ibm,get-xive returns %d\n",
- virq, status);
+ printk(KERN_ERR "%s: ibm,get-xive irq=%u returns %d\n",
+ __func__, irq, status);
goto unlock;
}
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
index 1c5321ae8f2..d1d5a83039a 100644
--- a/arch/powerpc/platforms/pseries/xics.h
+++ b/arch/powerpc/platforms/pseries/xics.h
@@ -12,20 +12,12 @@
#ifndef _POWERPC_KERNEL_XICS_H
#define _POWERPC_KERNEL_XICS_H
-#include <linux/cache.h>
-
extern void xics_init_IRQ(void);
extern void xics_setup_cpu(void);
extern void xics_teardown_cpu(void);
extern void xics_kexec_teardown_cpu(int secondary);
-extern void xics_cause_IPI(int cpu);
-extern void xics_request_IPIs(void);
extern void xics_migrate_irqs_away(void);
-
-struct xics_ipi_struct {
- volatile unsigned long value;
-} ____cacheline_aligned;
-
-extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
+extern int smp_xics_probe(void);
+extern void smp_xics_message_pass(int target, int msg);
#endif /* _POWERPC_KERNEL_XICS_H */
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig
index 72fb35b9ebc..396582835cb 100644
--- a/arch/powerpc/sysdev/Kconfig
+++ b/arch/powerpc/sysdev/Kconfig
@@ -6,3 +6,9 @@ config PPC4xx_PCI_EXPRESS
bool
depends on PCI && 4xx
default n
+
+config PPC_MSI_BITMAP
+ bool
+ depends on PCI_MSI
+ default y if MPIC
+ default y if FSL_PCI
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index a90054b56d5..a44709a94f9 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -5,6 +5,7 @@ endif
mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o
obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y)
fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o
+obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o
obj-$(CONFIG_PPC_MPC106) += grackle.o
obj-$(CONFIG_PPC_DCR_NATIVE) += dcr-low.o
@@ -15,6 +16,7 @@ obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y)
obj-$(CONFIG_FSL_LBC) += fsl_lbc.o
obj-$(CONFIG_FSL_GTM) += fsl_gtm.o
+obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o
obj-$(CONFIG_RAPIDIO) += fsl_rio.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
@@ -36,15 +38,12 @@ ifeq ($(CONFIG_PCI),y)
obj-$(CONFIG_4xx) += ppc4xx_pci.o
endif
-# Temporary hack until we have migrated to asm-powerpc
-ifeq ($(ARCH),powerpc)
obj-$(CONFIG_CPM) += cpm_common.o
obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o
obj-$(CONFIG_QUICC_ENGINE) += cpm_common.o
obj-$(CONFIG_PPC_DCR) += dcr.o
obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o
obj-$(CONFIG_UCODE_PATCH) += micropatch.o
-endif
ifeq ($(CONFIG_SUSPEND),y)
obj-$(CONFIG_6xx) += 6xx-suspend.o
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c
index 4a04823e842..490473ce810 100644
--- a/arch/powerpc/sysdev/cpm1.c
+++ b/arch/powerpc/sysdev/cpm1.c
@@ -546,15 +546,11 @@ static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio)
return !!(in_be16(&iop->dat) & pin_mask);
}
-static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static void __cpm1_gpio16_set(struct of_mm_gpio_chip *mm_gc, u16 pin_mask,
+ int value)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u16 pin_mask = 1 << (15 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
if (value)
cpm1_gc->cpdata |= pin_mask;
@@ -562,6 +558,18 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
cpm1_gc->cpdata &= ~pin_mask;
out_be16(&iop->dat, cpm1_gc->cpdata);
+}
+
+static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
+ unsigned long flags;
+ u16 pin_mask = 1 << (15 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ __cpm1_gpio16_set(mm_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
@@ -569,14 +577,17 @@ static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value)
static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- u16 pin_mask;
+ unsigned long flags;
+ u16 pin_mask = 1 << (15 - gpio);
- pin_mask = 1 << (15 - gpio);
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
setbits16(&iop->dir, pin_mask);
+ __cpm1_gpio16_set(mm_gc, pin_mask, val);
- cpm1_gpio16_set(gc, gpio, val);
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
@@ -584,13 +595,17 @@ static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc);
struct cpm_ioport16 __iomem *iop = mm_gc->regs;
- u16 pin_mask;
+ unsigned long flags;
+ u16 pin_mask = 1 << (15 - gpio);
- pin_mask = 1 << (15 - gpio);
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
clrbits16(&iop->dir, pin_mask);
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+
return 0;
}
@@ -655,15 +670,11 @@ static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio)
return !!(in_be32(&iop->dat) & pin_mask);
}
-static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+static void __cpm1_gpio32_set(struct of_mm_gpio_chip *mm_gc, u32 pin_mask,
+ int value)
{
- struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- unsigned long flags;
- u32 pin_mask = 1 << (31 - gpio);
-
- spin_lock_irqsave(&cpm1_gc->lock, flags);
if (value)
cpm1_gc->cpdata |= pin_mask;
@@ -671,6 +682,18 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
cpm1_gc->cpdata &= ~pin_mask;
out_be32(&iop->dat, cpm1_gc->cpdata);
+}
+
+static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+ struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
+
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
+
+ __cpm1_gpio32_set(mm_gc, pin_mask, value);
spin_unlock_irqrestore(&cpm1_gc->lock, flags);
}
@@ -678,14 +701,17 @@ static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value)
static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- u32 pin_mask;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
- pin_mask = 1 << (31 - gpio);
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
setbits32(&iop->dir, pin_mask);
+ __cpm1_gpio32_set(mm_gc, pin_mask, val);
- cpm1_gpio32_set(gc, gpio, val);
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
return 0;
}
@@ -693,13 +719,17 @@ static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc);
struct cpm_ioport32b __iomem *iop = mm_gc->regs;
- u32 pin_mask;
+ unsigned long flags;
+ u32 pin_mask = 1 << (31 - gpio);
- pin_mask = 1 << (31 - gpio);
+ spin_lock_irqsave(&cpm1_gc->lock, flags);
clrbits32(&iop->dir, pin_mask);
+ spin_unlock_irqrestore(&cpm1_gc->lock, flags);
+
return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_lbc.c b/arch/powerpc/sysdev/fsl_lbc.c
index 422c8faef59..0494ee55920 100644
--- a/arch/powerpc/sysdev/fsl_lbc.c
+++ b/arch/powerpc/sysdev/fsl_lbc.c
@@ -11,14 +11,19 @@
* (at your option) any later version.
*/
+#include <linux/init.h>
+#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/io.h>
#include <linux/of.h>
+#include <asm/prom.h>
#include <asm/fsl_lbc.h>
-spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
-
-struct fsl_lbc_regs __iomem *fsl_lbc_regs;
-EXPORT_SYMBOL(fsl_lbc_regs);
+static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
+static struct fsl_lbc_regs __iomem *fsl_lbc_regs;
static char __initdata *compat_lbc[] = {
"fsl,pq2-localbus",
@@ -127,3 +132,43 @@ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
return 0;
}
EXPORT_SYMBOL(fsl_upm_find);
+
+/**
+ * fsl_upm_run_pattern - actually run an UPM pattern
+ * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find
+ * @io_base: remapped pointer to where memory access should happen
+ * @mar: MAR register content during pattern execution
+ *
+ * This function triggers dummy write to the memory specified by the io_base,
+ * thus UPM pattern actually executed. Note that mar usage depends on the
+ * pre-programmed AMX bits in the UPM RAM.
+ */
+int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_lbc_lock, flags);
+
+ out_be32(&fsl_lbc_regs->mar, mar << (32 - upm->width));
+
+ switch (upm->width) {
+ case 8:
+ out_8(io_base, 0x0);
+ break;
+ case 16:
+ out_be16(io_base, 0x0);
+ break;
+ case 32:
+ out_be32(io_base, 0x0);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ spin_unlock_irqrestore(&fsl_lbc_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(fsl_upm_run_pattern);
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index 2c5187cc8a2..f25ce818d40 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -14,7 +14,6 @@
*/
#include <linux/irq.h>
#include <linux/bootmem.h>
-#include <linux/bitmap.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/of_platform.h>
@@ -67,95 +66,22 @@ static struct irq_host_ops fsl_msi_host_ops = {
.map = fsl_msi_host_map,
};
-static irq_hw_number_t fsl_msi_alloc_hwirqs(struct fsl_msi *msi, int num)
-{
- unsigned long flags;
- int order = get_count_order(num);
- int offset;
-
- spin_lock_irqsave(&msi->bitmap_lock, flags);
-
- offset = bitmap_find_free_region(msi->fsl_msi_bitmap,
- NR_MSI_IRQS, order);
-
- spin_unlock_irqrestore(&msi->bitmap_lock, flags);
-
- pr_debug("%s: allocated 0x%x (2^%d) at offset 0x%x\n",
- __func__, num, order, offset);
-
- return offset;
-}
-
-static void fsl_msi_free_hwirqs(struct fsl_msi *msi, int offset, int num)
-{
- unsigned long flags;
- int order = get_count_order(num);
-
- pr_debug("%s: freeing 0x%x (2^%d) at offset 0x%x\n",
- __func__, num, order, offset);
-
- spin_lock_irqsave(&msi->bitmap_lock, flags);
- bitmap_release_region(msi->fsl_msi_bitmap, offset, order);
- spin_unlock_irqrestore(&msi->bitmap_lock, flags);
-}
-
-static int fsl_msi_free_dt_hwirqs(struct fsl_msi *msi)
-{
- int i;
- int len;
- const u32 *p;
-
- bitmap_allocate_region(msi->fsl_msi_bitmap, 0,
- get_count_order(NR_MSI_IRQS));
-
- p = of_get_property(msi->of_node, "msi-available-ranges", &len);
-
- if (!p) {
- /* No msi-available-ranges property,
- * All the 256 MSI interrupts can be used
- */
- fsl_msi_free_hwirqs(msi, 0, 0x100);
- return 0;
- }
-
- if ((len % (2 * sizeof(u32))) != 0) {
- printk(KERN_WARNING "fsl_msi: Malformed msi-available-ranges "
- "property on %s\n", msi->of_node->full_name);
- return -EINVAL;
- }
-
- /* Format is: (<u32 start> <u32 count>)+ */
- len /= 2 * sizeof(u32);
- for (i = 0; i < len; i++, p += 2)
- fsl_msi_free_hwirqs(msi, *p, *(p + 1));
-
- return 0;
-}
-
static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
{
int rc;
- int size = BITS_TO_LONGS(NR_MSI_IRQS) * sizeof(u32);
- msi_data->fsl_msi_bitmap = kzalloc(size, GFP_KERNEL);
+ rc = msi_bitmap_alloc(&msi_data->bitmap, NR_MSI_IRQS,
+ msi_data->irqhost->of_node);
+ if (rc)
+ return rc;
- if (msi_data->fsl_msi_bitmap == NULL) {
- pr_debug("%s: ENOMEM allocating allocator bitmap!\n",
- __func__);
- return -ENOMEM;
+ rc = msi_bitmap_reserve_dt_hwirqs(&msi_data->bitmap);
+ if (rc < 0) {
+ msi_bitmap_free(&msi_data->bitmap);
+ return rc;
}
- rc = fsl_msi_free_dt_hwirqs(msi_data);
- if (rc)
- goto out_free;
-
return 0;
-out_free:
- kfree(msi_data->fsl_msi_bitmap);
-
- msi_data->fsl_msi_bitmap = NULL;
- return rc;
-
}
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
@@ -175,7 +101,8 @@ static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
if (entry->irq == NO_IRQ)
continue;
set_irq_msi(entry->irq, NULL);
- fsl_msi_free_hwirqs(msi_data, virq_to_hw(entry->irq), 1);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap,
+ virq_to_hw(entry->irq), 1);
irq_dispose_mapping(entry->irq);
}
@@ -197,15 +124,14 @@ static void fsl_compose_msi_msg(struct pci_dev *pdev, int hwirq,
static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
- irq_hw_number_t hwirq;
- int rc;
+ int rc, hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
struct fsl_msi *msi_data = fsl_msi;
list_for_each_entry(entry, &pdev->msi_list, list) {
- hwirq = fsl_msi_alloc_hwirqs(msi_data, 1);
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_data->bitmap, 1);
if (hwirq < 0) {
rc = hwirq;
pr_debug("%s: fail allocating msi interrupt\n",
@@ -216,9 +142,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
virq = irq_create_mapping(msi_data->irqhost, hwirq);
if (virq == NO_IRQ) {
- pr_debug("%s: fail mapping hwirq 0x%lx\n",
+ pr_debug("%s: fail mapping hwirq 0x%x\n",
__func__, hwirq);
- fsl_msi_free_hwirqs(msi_data, hwirq, 1);
+ msi_bitmap_free_hwirqs(&msi_data->bitmap, hwirq, 1);
rc = -ENOSPC;
goto out_free;
}
@@ -317,14 +243,11 @@ static int __devinit fsl_of_msi_probe(struct of_device *dev,
goto error_out;
}
- msi->of_node = of_node_get(dev->node);
+ msi->irqhost = irq_alloc_host(dev->node, IRQ_HOST_MAP_LINEAR,
+ NR_MSI_IRQS, &fsl_msi_host_ops, 0);
- msi->irqhost = irq_alloc_host(of_node_get(dev->node),
- IRQ_HOST_MAP_LINEAR,
- NR_MSI_IRQS, &fsl_msi_host_ops, 0);
if (msi->irqhost == NULL) {
dev_err(&dev->dev, "No memory for MSI irqhost\n");
- of_node_put(dev->node);
err = -ENOMEM;
goto error_out;
}
diff --git a/arch/powerpc/sysdev/fsl_msi.h b/arch/powerpc/sysdev/fsl_msi.h
index a653468521f..331c7e7025b 100644
--- a/arch/powerpc/sysdev/fsl_msi.h
+++ b/arch/powerpc/sysdev/fsl_msi.h
@@ -13,6 +13,8 @@
#ifndef _POWERPC_SYSDEV_FSL_MSI_H
#define _POWERPC_SYSDEV_FSL_MSI_H
+#include <asm/msi_bitmap.h>
+
#define NR_MSI_REG 8
#define IRQS_PER_MSI_REG 32
#define NR_MSI_IRQS (NR_MSI_REG * IRQS_PER_MSI_REG)
@@ -22,9 +24,6 @@
#define FSL_PIC_IP_IPIC 0x00000002
struct fsl_msi {
- /* Device node of the MSI interrupt*/
- struct device_node *of_node;
-
struct irq_host *irqhost;
unsigned long cascade_irq;
@@ -34,8 +33,7 @@ struct fsl_msi {
void __iomem *msi_regs;
u32 feature;
- unsigned long *fsl_msi_bitmap;
- spinlock_t bitmap_lock;
+ struct msi_bitmap bitmap;
};
#endif /* _POWERPC_SYSDEV_FSL_MSI_H */
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 61e6d77efa4..5b264eb4b1f 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -1,7 +1,7 @@
/*
- * MPC85xx/86xx PCI/PCIE support routing.
+ * MPC83xx/85xx/86xx PCI/PCIE support routing.
*
- * Copyright 2007 Freescale Semiconductor, Inc
+ * Copyright 2007,2008 Freescale Semiconductor, Inc
*
* Initial author: Xianghua Xiao <x.xiao@freescale.com>
* Recode: ZHANG WEI <wei.zhang@freescale.com>
@@ -251,20 +251,47 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header);
DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header);
#endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */
-#if defined(CONFIG_PPC_83xx)
+#if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x)
int __init mpc83xx_add_bridge(struct device_node *dev)
{
int len;
struct pci_controller *hose;
- struct resource rsrc;
+ struct resource rsrc_reg;
+ struct resource rsrc_cfg;
const int *bus_range;
- int primary = 1, has_address = 0;
- phys_addr_t immr = get_immrbase();
+ int primary;
pr_debug("Adding PCI host bridge %s\n", dev->full_name);
/* Fetch host bridge registers address */
- has_address = (of_address_to_resource(dev, 0, &rsrc) == 0);
+ if (of_address_to_resource(dev, 0, &rsrc_reg)) {
+ printk(KERN_WARNING "Can't get pci register base!\n");
+ return -ENOMEM;
+ }
+
+ memset(&rsrc_cfg, 0, sizeof(rsrc_cfg));
+
+ if (of_address_to_resource(dev, 1, &rsrc_cfg)) {
+ printk(KERN_WARNING
+ "No pci config register base in dev tree, "
+ "using default\n");
+ /*
+ * MPC83xx supports up to two host controllers
+ * one at 0x8500 has config space registers at 0x8300
+ * one at 0x8600 has config space registers at 0x8380
+ */
+ if ((rsrc_reg.start & 0xfffff) == 0x8500)
+ rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8300;
+ else if ((rsrc_reg.start & 0xfffff) == 0x8600)
+ rsrc_cfg.start = (rsrc_reg.start & 0xfff00000) + 0x8380;
+ }
+ /*
+ * Controller at offset 0x8500 is primary
+ */
+ if ((rsrc_reg.start & 0xfffff) == 0x8500)
+ primary = 1;
+ else
+ primary = 0;
/* Get bus range if any */
bus_range = of_get_property(dev, "bus-range", &len);
@@ -281,22 +308,11 @@ int __init mpc83xx_add_bridge(struct device_node *dev)
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
- /* MPC83xx supports up to two host controllers one at 0x8500 from immrbar
- * the other at 0x8600, we consider the 0x8500 the primary controller
- */
- /* PCI 1 */
- if ((rsrc.start & 0xfffff) == 0x8500) {
- setup_indirect_pci(hose, immr + 0x8300, immr + 0x8304, 0);
- }
- /* PCI 2 */
- if ((rsrc.start & 0xfffff) == 0x8600) {
- setup_indirect_pci(hose, immr + 0x8380, immr + 0x8384, 0);
- primary = 0;
- }
+ setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 4, 0);
- printk(KERN_INFO "Found MPC83xx PCI host bridge at 0x%016llx. "
+ printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. "
"Firmware bus number: %d->%d\n",
- (unsigned long long)rsrc.start, hose->first_busno,
+ (unsigned long long)rsrc_reg.start, hose->first_busno,
hose->last_busno);
pr_debug(" ->Hose at 0x%p, cfg_addr=0x%p,cfg_data=0x%p\n",
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 214388e1180..01b884b2569 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -412,53 +412,6 @@ err:
arch_initcall(gfar_of_init);
-
-#ifdef CONFIG_PPC_83xx
-static int __init mpc83xx_wdt_init(void)
-{
- struct resource r;
- struct device_node *np;
- struct platform_device *dev;
- u32 freq = fsl_get_sys_freq();
- int ret;
-
- np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt");
-
- if (!np) {
- ret = -ENODEV;
- goto nodev;
- }
-
- memset(&r, 0, sizeof(r));
-
- ret = of_address_to_resource(np, 0, &r);
- if (ret)
- goto err;
-
- dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1);
- if (IS_ERR(dev)) {
- ret = PTR_ERR(dev);
- goto err;
- }
-
- ret = platform_device_add_data(dev, &freq, sizeof(freq));
- if (ret)
- goto unreg;
-
- of_node_put(np);
- return 0;
-
-unreg:
- platform_device_unregister(dev);
-err:
- of_node_put(np);
-nodev:
- return ret;
-}
-
-arch_initcall(mpc83xx_wdt_init);
-#endif
-
static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
{
if (!phy_type)
@@ -767,42 +720,6 @@ void fsl_rstcr_restart(char *cmd)
#endif
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-struct platform_diu_data_ops diu_ops = {
- .diu_size = 1280 * 1024 * 4, /* default one 1280x1024 buffer */
-};
+struct platform_diu_data_ops diu_ops;
EXPORT_SYMBOL(diu_ops);
-
-int __init preallocate_diu_videomemory(void)
-{
- pr_debug("diu_size=%lu\n", diu_ops.diu_size);
-
- diu_ops.diu_mem = __alloc_bootmem(diu_ops.diu_size, 8, 0);
- if (!diu_ops.diu_mem) {
- printk(KERN_ERR "fsl-diu: cannot allocate %lu bytes\n",
- diu_ops.diu_size);
- return -ENOMEM;
- }
-
- pr_debug("diu_mem=%p\n", diu_ops.diu_mem);
-
- rh_init(&diu_ops.diu_rh_info, 4096, ARRAY_SIZE(diu_ops.diu_rh_block),
- diu_ops.diu_rh_block);
- return rh_attach_region(&diu_ops.diu_rh_info,
- (unsigned long) diu_ops.diu_mem,
- diu_ops.diu_size);
-}
-
-static int __init early_parse_diufb(char *p)
-{
- if (!p)
- return 1;
-
- diu_ops.diu_size = _ALIGN_UP(memparse(p, &p), 8);
-
- pr_debug("diu_size=%lu\n", diu_ops.diu_size);
-
- return 0;
-}
-early_param("diufb", early_parse_diufb);
-
#endif
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 02429988735..60f7f227327 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -20,14 +20,7 @@ extern int fsl_spi_init(struct spi_board_info *board_infos,
extern void fsl_rstcr_restart(char *cmd);
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
-#include <linux/bootmem.h>
-#include <asm/rheap.h>
struct platform_diu_data_ops {
- rh_block_t diu_rh_block[16];
- rh_info_t diu_rh_info;
- unsigned long diu_size;
- void *diu_mem;
-
unsigned int (*get_pixel_format) (unsigned int bits_per_pixel,
int monitor_port);
void (*set_gamma_table) (int monitor_port, char *gamma_table_base);
@@ -38,7 +31,6 @@ struct platform_diu_data_ops {
};
extern struct platform_diu_data_ops diu_ops;
-int __init preallocate_diu_videomemory(void);
#endif
#endif
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
new file mode 100644
index 00000000000..103eace3619
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -0,0 +1,171 @@
+/*
+ * GPIOs on MPC8349/8572/8610 and compatible
+ *
+ * Copyright (C) 2008 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/kernel.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+
+#define MPC8XXX_GPIO_PINS 32
+
+#define GPIO_DIR 0x00
+#define GPIO_ODR 0x04
+#define GPIO_DAT 0x08
+#define GPIO_IER 0x0c
+#define GPIO_IMR 0x10
+#define GPIO_ICR 0x14
+
+struct mpc8xxx_gpio_chip {
+ struct of_mm_gpio_chip mm_gc;
+ spinlock_t lock;
+
+ /*
+ * shadowed data register to be able to clear/set output pins in
+ * open drain mode safely
+ */
+ u32 data;
+};
+
+static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
+{
+ return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
+}
+
+static inline struct mpc8xxx_gpio_chip *
+to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
+{
+ return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
+}
+
+static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
+{
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+
+ mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
+}
+
+static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+
+ return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
+}
+
+static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+ if (val)
+ mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
+ else
+ mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
+
+ out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
+
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+}
+
+static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+ struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+ clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+ return 0;
+}
+
+static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
+ unsigned long flags;
+
+ mpc8xxx_gpio_set(gc, gpio, val);
+
+ spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
+
+ setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
+
+ spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
+
+ return 0;
+}
+
+static void __init mpc8xxx_add_controller(struct device_node *np)
+{
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc;
+ struct of_mm_gpio_chip *mm_gc;
+ struct of_gpio_chip *of_gc;
+ struct gpio_chip *gc;
+ int ret;
+
+ mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
+ if (!mpc8xxx_gc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ spin_lock_init(&mpc8xxx_gc->lock);
+
+ mm_gc = &mpc8xxx_gc->mm_gc;
+ of_gc = &mm_gc->of_gc;
+ gc = &of_gc->gc;
+
+ mm_gc->save_regs = mpc8xxx_gpio_save_regs;
+ of_gc->gpio_cells = 2;
+ gc->ngpio = MPC8XXX_GPIO_PINS;
+ gc->direction_input = mpc8xxx_gpio_dir_in;
+ gc->direction_output = mpc8xxx_gpio_dir_out;
+ gc->get = mpc8xxx_gpio_get;
+ gc->set = mpc8xxx_gpio_set;
+
+ ret = of_mm_gpiochip_add(np, mm_gc);
+ if (ret)
+ goto err;
+
+ return;
+
+err:
+ pr_err("%s: registration failed with status %d\n",
+ np->full_name, ret);
+ kfree(mpc8xxx_gc);
+
+ return;
+}
+
+static int __init mpc8xxx_add_gpiochips(void)
+{
+ struct device_node *np;
+
+ for_each_compatible_node(np, NULL, "fsl,mpc8349-gpio")
+ mpc8xxx_add_controller(np);
+
+ for_each_compatible_node(np, NULL, "fsl,mpc8572-gpio")
+ mpc8xxx_add_controller(np);
+
+ for_each_compatible_node(np, NULL, "fsl,mpc8610-gpio")
+ mpc8xxx_add_controller(np);
+
+ return 0;
+}
+arch_initcall(mpc8xxx_add_gpiochips);
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h
index fbf8a266941..6209c62a426 100644
--- a/arch/powerpc/sysdev/mpic.h
+++ b/arch/powerpc/sysdev/mpic.h
@@ -14,8 +14,6 @@
#ifdef CONFIG_PCI_MSI
extern void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq);
extern int mpic_msi_init_allocator(struct mpic *mpic);
-extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num);
-extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num);
extern int mpic_u3msi_init(struct mpic *mpic);
extern int mpic_pasemi_msi_init(struct mpic *mpic);
#else
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c
index de3e5e8bc32..1d44eee80fa 100644
--- a/arch/powerpc/sysdev/mpic_msi.c
+++ b/arch/powerpc/sysdev/mpic_msi.c
@@ -15,59 +15,17 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
#include <sysdev/mpic.h>
-static void __mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
-{
- pr_debug("mpic: reserving hwirq 0x%lx\n", hwirq);
- bitmap_allocate_region(mpic->hwirq_bitmap, hwirq, 0);
-}
-
void mpic_msi_reserve_hwirq(struct mpic *mpic, irq_hw_number_t hwirq)
{
- unsigned long flags;
-
/* The mpic calls this even when there is no allocator setup */
- if (!mpic->hwirq_bitmap)
+ if (!mpic->msi_bitmap.bitmap)
return;
- spin_lock_irqsave(&mpic->bitmap_lock, flags);
- __mpic_msi_reserve_hwirq(mpic, hwirq);
- spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
-}
-
-irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num)
-{
- unsigned long flags;
- int offset, order = get_count_order(num);
-
- spin_lock_irqsave(&mpic->bitmap_lock, flags);
- /*
- * This is fast, but stricter than we need. We might want to add
- * a fallback routine which does a linear search with no alignment.
- */
- offset = bitmap_find_free_region(mpic->hwirq_bitmap, mpic->irq_count,
- order);
- spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
-
- pr_debug("mpic: allocated 0x%x (2^%d) at offset 0x%x\n",
- num, order, offset);
-
- return offset;
-}
-
-void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num)
-{
- unsigned long flags;
- int order = get_count_order(num);
-
- pr_debug("mpic: freeing 0x%x (2^%d) at offset 0x%x\n",
- num, order, offset);
-
- spin_lock_irqsave(&mpic->bitmap_lock, flags);
- bitmap_release_region(mpic->hwirq_bitmap, offset, order);
- spin_unlock_irqrestore(&mpic->bitmap_lock, flags);
+ msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
}
#ifdef CONFIG_MPIC_U3_HT_IRQS
@@ -83,13 +41,13 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
/* Reserve source numbers we know are reserved in the HW */
for (i = 0; i < 8; i++)
- __mpic_msi_reserve_hwirq(mpic, i);
+ msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
for (i = 42; i < 46; i++)
- __mpic_msi_reserve_hwirq(mpic, i);
+ msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
for (i = 100; i < 105; i++)
- __mpic_msi_reserve_hwirq(mpic, i);
+ msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i);
np = NULL;
while ((np = of_find_all_nodes(np))) {
@@ -99,7 +57,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
while (of_irq_map_one(np, index++, &oirq) == 0) {
ops->xlate(mpic->irqhost, NULL, oirq.specifier,
oirq.size, &hwirq, &flags);
- __mpic_msi_reserve_hwirq(mpic, hwirq);
+ msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, hwirq);
}
}
@@ -112,70 +70,25 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic)
}
#endif
-static int mpic_msi_reserve_dt_hwirqs(struct mpic *mpic)
-{
- int i, len;
- const u32 *p;
-
- p = of_get_property(mpic->irqhost->of_node,
- "msi-available-ranges", &len);
- if (!p) {
- pr_debug("mpic: no msi-available-ranges property found on %s\n",
- mpic->irqhost->of_node->full_name);
- return -ENODEV;
- }
-
- if (len % 8 != 0) {
- printk(KERN_WARNING "mpic: Malformed msi-available-ranges "
- "property on %s\n", mpic->irqhost->of_node->full_name);
- return -EINVAL;
- }
-
- bitmap_allocate_region(mpic->hwirq_bitmap, 0,
- get_count_order(mpic->irq_count));
-
- /* Format is: (<u32 start> <u32 count>)+ */
- len /= sizeof(u32);
- for (i = 0; i < len / 2; i++, p += 2)
- mpic_msi_free_hwirqs(mpic, *p, *(p + 1));
-
- return 0;
-}
-
int mpic_msi_init_allocator(struct mpic *mpic)
{
- int rc, size;
-
- BUG_ON(mpic->hwirq_bitmap);
- spin_lock_init(&mpic->bitmap_lock);
+ int rc;
- size = BITS_TO_LONGS(mpic->irq_count) * sizeof(long);
- pr_debug("mpic: allocator bitmap size is 0x%x bytes\n", size);
+ rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count,
+ mpic->irqhost->of_node);
+ if (rc)
+ return rc;
- mpic->hwirq_bitmap = alloc_maybe_bootmem(size, GFP_KERNEL);
-
- if (!mpic->hwirq_bitmap) {
- pr_debug("mpic: ENOMEM allocating allocator bitmap!\n");
- return -ENOMEM;
- }
-
- memset(mpic->hwirq_bitmap, 0, size);
-
- rc = mpic_msi_reserve_dt_hwirqs(mpic);
- if (rc) {
+ rc = msi_bitmap_reserve_dt_hwirqs(&mpic->msi_bitmap);
+ if (rc > 0) {
if (mpic->flags & MPIC_U3_HT_IRQS)
rc = mpic_msi_reserve_u3_hwirqs(mpic);
- if (rc)
- goto out_free;
+ if (rc) {
+ msi_bitmap_free(&mpic->msi_bitmap);
+ return rc;
+ }
}
return 0;
-
- out_free:
- if (mem_init_done)
- kfree(mpic->hwirq_bitmap);
-
- mpic->hwirq_bitmap = NULL;
- return rc;
}
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
index 68aff607667..656cb772b69 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
@@ -22,6 +22,7 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
#include "mpic.h"
@@ -81,8 +82,8 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
continue;
set_irq_msi(entry->irq, NULL);
- mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq),
- ALLOC_CHUNK);
+ msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
+ virq_to_hw(entry->irq), ALLOC_CHUNK);
irq_dispose_mapping(entry->irq);
}
@@ -91,11 +92,10 @@ static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
- irq_hw_number_t hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
- int ret;
+ int hwirq;
pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
pdev, nvec, type);
@@ -109,17 +109,19 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
* few MSIs for someone, but restrictions will apply to how the
* sources can be changed independently.
*/
- ret = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK);
- hwirq = ret;
- if (ret < 0) {
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap,
+ ALLOC_CHUNK);
+ if (hwirq < 0) {
pr_debug("pasemi_msi: failed allocating hwirq\n");
return hwirq;
}
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) {
- pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq);
- mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK);
+ pr_debug("pasemi_msi: failed mapping hwirq 0x%x\n",
+ hwirq);
+ msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq,
+ ALLOC_CHUNK);
return -ENOSPC;
}
@@ -133,8 +135,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
set_irq_chip(virq, &mpic_pasemi_msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
- pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%x\n",
- virq, hwirq, msg.address_lo);
+ pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%x) " \
+ "addr 0x%x\n", virq, hwirq, msg.address_lo);
/* Likewise, the device writes [0...511] into the target
* register to generate MSI [512...1023]
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index 6e2f8686fdf..0a8f5a9e87c 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -16,6 +16,7 @@
#include <asm/prom.h>
#include <asm/hw_irq.h>
#include <asm/ppc-pci.h>
+#include <asm/msi_bitmap.h>
#include "mpic.h"
@@ -101,7 +102,8 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
continue;
set_irq_msi(entry->irq, NULL);
- mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), 1);
+ msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap,
+ virq_to_hw(entry->irq), 1);
irq_dispose_mapping(entry->irq);
}
@@ -110,29 +112,27 @@ static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
- irq_hw_number_t hwirq;
unsigned int virq;
struct msi_desc *entry;
struct msi_msg msg;
u64 addr;
- int ret;
+ int hwirq;
addr = find_ht_magic_addr(pdev);
msg.address_lo = addr & 0xFFFFFFFF;
msg.address_hi = addr >> 32;
list_for_each_entry(entry, &pdev->msi_list, list) {
- ret = mpic_msi_alloc_hwirqs(msi_mpic, 1);
- if (ret < 0) {
+ hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
+ if (hwirq < 0) {
pr_debug("u3msi: failed allocating hwirq\n");
- return ret;
+ return hwirq;
}
- hwirq = ret;
virq = irq_create_mapping(msi_mpic->irqhost, hwirq);
if (virq == NO_IRQ) {
- pr_debug("u3msi: failed mapping hwirq 0x%lx\n", hwirq);
- mpic_msi_free_hwirqs(msi_mpic, hwirq, 1);
+ pr_debug("u3msi: failed mapping hwirq 0x%x\n", hwirq);
+ msi_bitmap_free_hwirqs(&msi_mpic->msi_bitmap, hwirq, 1);
return -ENOSPC;
}
@@ -140,8 +140,8 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
set_irq_chip(virq, &mpic_u3msi_chip);
set_irq_type(virq, IRQ_TYPE_EDGE_RISING);
- pr_debug("u3msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n",
- virq, hwirq, addr);
+ pr_debug("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
+ virq, hwirq, (unsigned long)addr);
msg.data = hwirq;
write_msi_msg(virq, &msg);
diff --git a/arch/powerpc/sysdev/msi_bitmap.c b/arch/powerpc/sysdev/msi_bitmap.c
new file mode 100644
index 00000000000..f84217b8863
--- /dev/null
+++ b/arch/powerpc/sysdev/msi_bitmap.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2006-2008, Michael Ellerman, IBM Corporation.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitmap.h>
+#include <asm/msi_bitmap.h>
+
+int msi_bitmap_alloc_hwirqs(struct msi_bitmap *bmp, int num)
+{
+ unsigned long flags;
+ int offset, order = get_count_order(num);
+
+ spin_lock_irqsave(&bmp->lock, flags);
+ /*
+ * This is fast, but stricter than we need. We might want to add
+ * a fallback routine which does a linear search with no alignment.
+ */
+ offset = bitmap_find_free_region(bmp->bitmap, bmp->irq_count, order);
+ spin_unlock_irqrestore(&bmp->lock, flags);
+
+ pr_debug("msi_bitmap: allocated 0x%x (2^%d) at offset 0x%x\n",
+ num, order, offset);
+
+ return offset;
+}
+
+void msi_bitmap_free_hwirqs(struct msi_bitmap *bmp, unsigned int offset,
+ unsigned int num)
+{
+ unsigned long flags;
+ int order = get_count_order(num);
+
+ pr_debug("msi_bitmap: freeing 0x%x (2^%d) at offset 0x%x\n",
+ num, order, offset);
+
+ spin_lock_irqsave(&bmp->lock, flags);
+ bitmap_release_region(bmp->bitmap, offset, order);
+ spin_unlock_irqrestore(&bmp->lock, flags);
+}
+
+void msi_bitmap_reserve_hwirq(struct msi_bitmap *bmp, unsigned int hwirq)
+{
+ unsigned long flags;
+
+ pr_debug("msi_bitmap: reserving hwirq 0x%x\n", hwirq);
+
+ spin_lock_irqsave(&bmp->lock, flags);
+ bitmap_allocate_region(bmp->bitmap, hwirq, 0);
+ spin_unlock_irqrestore(&bmp->lock, flags);
+}
+
+/**
+ * msi_bitmap_reserve_dt_hwirqs - Reserve irqs specified in the device tree.
+ * @bmp: pointer to the MSI bitmap.
+ *
+ * Looks in the device tree to see if there is a property specifying which
+ * irqs can be used for MSI. If found those irqs reserved in the device tree
+ * are reserved in the bitmap.
+ *
+ * Returns 0 for success, < 0 if there was an error, and > 0 if no property
+ * was found in the device tree.
+ **/
+int msi_bitmap_reserve_dt_hwirqs(struct msi_bitmap *bmp)
+{
+ int i, j, len;
+ const u32 *p;
+
+ if (!bmp->of_node)
+ return 1;
+
+ p = of_get_property(bmp->of_node, "msi-available-ranges", &len);
+ if (!p) {
+ pr_debug("msi_bitmap: no msi-available-ranges property " \
+ "found on %s\n", bmp->of_node->full_name);
+ return 1;
+ }
+
+ if (len % (2 * sizeof(u32)) != 0) {
+ printk(KERN_WARNING "msi_bitmap: Malformed msi-available-ranges"
+ " property on %s\n", bmp->of_node->full_name);
+ return -EINVAL;
+ }
+
+ bitmap_allocate_region(bmp->bitmap, 0, get_count_order(bmp->irq_count));
+
+ spin_lock(&bmp->lock);
+
+ /* Format is: (<u32 start> <u32 count>)+ */
+ len /= 2 * sizeof(u32);
+ for (i = 0; i < len; i++, p += 2) {
+ for (j = 0; j < *(p + 1); j++)
+ bitmap_release_region(bmp->bitmap, *p + j, 0);
+ }
+
+ spin_unlock(&bmp->lock);
+
+ return 0;
+}
+
+int msi_bitmap_alloc(struct msi_bitmap *bmp, unsigned int irq_count,
+ struct device_node *of_node)
+{
+ int size;
+
+ if (!irq_count)
+ return -EINVAL;
+
+ size = BITS_TO_LONGS(irq_count) * sizeof(long);
+ pr_debug("msi_bitmap: allocator bitmap size is 0x%x bytes\n", size);
+
+ bmp->bitmap = zalloc_maybe_bootmem(size, GFP_KERNEL);
+ if (!bmp->bitmap) {
+ pr_debug("msi_bitmap: ENOMEM allocating allocator bitmap!\n");
+ return -ENOMEM;
+ }
+
+ /* We zalloc'ed the bitmap, so all irqs are free by default */
+ spin_lock_init(&bmp->lock);
+ bmp->of_node = of_node_get(of_node);
+ bmp->irq_count = irq_count;
+
+ return 0;
+}
+
+void msi_bitmap_free(struct msi_bitmap *bmp)
+{
+ /* we can't free the bitmap we don't know if it's bootmem etc. */
+ of_node_put(bmp->of_node);
+ bmp->bitmap = NULL;
+}
+
+#ifdef CONFIG_MSI_BITMAP_SELFTEST
+
+#define check(x) \
+ if (!(x)) printk("msi_bitmap: test failed at line %d\n", __LINE__);
+
+void test_basics(void)
+{
+ struct msi_bitmap bmp;
+ int i, size = 512;
+
+ /* Can't allocate a bitmap of 0 irqs */
+ check(msi_bitmap_alloc(&bmp, 0, NULL) != 0);
+
+ /* of_node may be NULL */
+ check(0 == msi_bitmap_alloc(&bmp, size, NULL));
+
+ /* Should all be free by default */
+ check(0 == bitmap_find_free_region(bmp.bitmap, size,
+ get_count_order(size)));
+ bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+ /* With no node, there's no msi-available-ranges, so expect > 0 */
+ check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0);
+
+ /* Should all still be free */
+ check(0 == bitmap_find_free_region(bmp.bitmap, size,
+ get_count_order(size)));
+ bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+ /* Check we can fill it up and then no more */
+ for (i = 0; i < size; i++)
+ check(msi_bitmap_alloc_hwirqs(&bmp, 1) >= 0);
+
+ check(msi_bitmap_alloc_hwirqs(&bmp, 1) < 0);
+
+ /* Should all be allocated */
+ check(bitmap_find_free_region(bmp.bitmap, size, 0) < 0);
+
+ /* And if we free one we can then allocate another */
+ msi_bitmap_free_hwirqs(&bmp, size / 2, 1);
+ check(msi_bitmap_alloc_hwirqs(&bmp, 1) == size / 2);
+
+ msi_bitmap_free(&bmp);
+
+ /* Clients may check bitmap == NULL for "not-allocated" */
+ check(bmp.bitmap == NULL);
+
+ kfree(bmp.bitmap);
+}
+
+void test_of_node(void)
+{
+ u32 prop_data[] = { 10, 10, 25, 3, 40, 1, 100, 100, 200, 20 };
+ const char *expected_str = "0-9,20-24,28-39,41-99,220-255";
+ char *prop_name = "msi-available-ranges";
+ char *node_name = "/fakenode";
+ struct device_node of_node;
+ struct property prop;
+ struct msi_bitmap bmp;
+ int size = 256;
+ DECLARE_BITMAP(expected, size);
+
+ /* There should really be a struct device_node allocator */
+ memset(&of_node, 0, sizeof(of_node));
+ kref_init(&of_node.kref);
+ of_node.full_name = node_name;
+
+ check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
+
+ /* No msi-available-ranges, so expect > 0 */
+ check(msi_bitmap_reserve_dt_hwirqs(&bmp) > 0);
+
+ /* Should all still be free */
+ check(0 == bitmap_find_free_region(bmp.bitmap, size,
+ get_count_order(size)));
+ bitmap_release_region(bmp.bitmap, 0, get_count_order(size));
+
+ /* Now create a fake msi-available-ranges property */
+
+ /* There should really .. oh whatever */
+ memset(&prop, 0, sizeof(prop));
+ prop.name = prop_name;
+ prop.value = &prop_data;
+ prop.length = sizeof(prop_data);
+
+ of_node.properties = &prop;
+
+ /* msi-available-ranges, so expect == 0 */
+ check(msi_bitmap_reserve_dt_hwirqs(&bmp) == 0);
+
+ /* Check we got the expected result */
+ check(0 == bitmap_parselist(expected_str, expected, size));
+ check(bitmap_equal(expected, bmp.bitmap, size));
+
+ msi_bitmap_free(&bmp);
+ kfree(bmp.bitmap);
+}
+
+int msi_bitmap_selftest(void)
+{
+ printk(KERN_DEBUG "Running MSI bitmap self-tests ...\n");
+
+ test_basics();
+ test_of_node();
+
+ return 0;
+}
+late_initcall(msi_bitmap_selftest);
+#endif /* CONFIG_MSI_BITMAP_SELFTEST */
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c
index fb368dfde5d..9f6f73d584d 100644
--- a/arch/powerpc/sysdev/ppc4xx_pci.c
+++ b/arch/powerpc/sysdev/ppc4xx_pci.c
@@ -30,14 +30,12 @@
#include <asm/machdep.h>
#include <asm/dcr.h>
#include <asm/dcr-regs.h>
+#include <mm/mmu_decl.h>
#include "ppc4xx_pci.h"
static int dma_offset_set;
-/* Move that to a useable header */
-extern unsigned long total_memory;
-
#define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL))
#define U64_TO_U32_HIGH(val) ((u32)((val) >> 32))
@@ -105,7 +103,8 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
/* Default */
res->start = 0;
- res->end = size = 0x80000000;
+ size = 0x80000000;
+ res->end = size - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
/* Get dma-ranges property */
@@ -167,13 +166,13 @@ static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose,
*/
if (size < total_memory) {
printk(KERN_ERR "%s: dma-ranges too small "
- "(size=%llx total_memory=%lx)\n",
- hose->dn->full_name, size, total_memory);
+ "(size=%llx total_memory=%llx)\n",
+ hose->dn->full_name, size, (u64)total_memory);
return -ENXIO;
}
/* Check we are a power of 2 size and that base is a multiple of size*/
- if (!is_power_of_2(size) ||
+ if ((size & (size - 1)) != 0 ||
(res->start & (size - 1)) != 0) {
printk(KERN_ERR "%s: dma-ranges unaligned\n",
hose->dn->full_name);
@@ -277,9 +276,16 @@ static void __init ppc4xx_probe_pci_bridge(struct device_node *np)
const int *bus_range;
int primary = 0;
+ /* Check if device is enabled */
+ if (!of_device_is_available(np)) {
+ printk(KERN_INFO "%s: Port disabled via device-tree\n",
+ np->full_name);
+ return;
+ }
+
/* Fetch config space registers address */
if (of_address_to_resource(np, 0, &rsrc_cfg)) {
- printk(KERN_ERR "%s:Can't get PCI config register base !",
+ printk(KERN_ERR "%s: Can't get PCI config register base !",
np->full_name);
return;
}
@@ -810,7 +816,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
switch (port->index) {
case 0:
mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230);
- mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000136);
+ mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130);
mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006);
mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST,0x10000000);
@@ -821,10 +827,10 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
mtdcri(SDR0, PESDR1_460EX_L1CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L2CDRCTL, 0x00003230);
mtdcri(SDR0, PESDR1_460EX_L3CDRCTL, 0x00003230);
- mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000136);
- mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000136);
- mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000136);
- mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000136);
+ mtdcri(SDR0, PESDR1_460EX_L0DRV, 0x00000130);
+ mtdcri(SDR0, PESDR1_460EX_L1DRV, 0x00000130);
+ mtdcri(SDR0, PESDR1_460EX_L2DRV, 0x00000130);
+ mtdcri(SDR0, PESDR1_460EX_L3DRV, 0x00000130);
mtdcri(SDR0, PESDR1_460EX_L0CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_L1CLK, 0x00000006);
mtdcri(SDR0, PESDR1_460EX_L2CLK, 0x00000006);
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
index 1ce546462be..76ffbc48d4b 100644
--- a/arch/powerpc/sysdev/qe_lib/Kconfig
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -24,12 +24,3 @@ config QE_USB
bool
help
QE USB Host Controller support
-
-config QE_GPIO
- bool "QE GPIO support"
- depends on QUICC_ENGINE
- select GENERIC_GPIO
- select ARCH_REQUIRE_GPIOLIB
- help
- Say Y here if you're going to use hardware that connects to the
- QE GPIOs.
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 98e246dc023..4646382af34 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -279,22 +279,6 @@ asmlinkage long sys32_getegid16(void)
return high2lowgid(current->egid);
}
-/* 32-bit timeval and related flotsam. */
-
-static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
- return (!access_ok(VERIFY_READ, o, sizeof(*o)) ||
- (__get_user(o->tv_sec, &i->tv_sec) ||
- __get_user(o->tv_usec, &i->tv_usec)));
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
- return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
- (__put_user(i->tv_sec, &o->tv_sec) ||
- __put_user(i->tv_usec, &o->tv_usec)));
-}
-
/*
* sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.
*
@@ -362,41 +346,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
return sys_ftruncate(fd, (high << 32) | low);
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
- compat_ino_t ino;
- int err;
-
- if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- ino = stat->ino;
- if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
- return -EOVERFLOW;
-
- err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
- err |= put_user(stat->ino, &statbuf->st_ino);
- err |= put_user(stat->mode, &statbuf->st_mode);
- err |= put_user(stat->nlink, &statbuf->st_nlink);
- err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
- err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
- err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
- err |= put_user(stat->size, &statbuf->st_size);
- err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
- err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
- err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
- err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
- err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
- err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
- err |= put_user(stat->blksize, &statbuf->st_blksize);
- err |= put_user(stat->blocks, &statbuf->st_blocks);
-/* fixme
- err |= put_user(0, &statbuf->__unused4[0]);
- err |= put_user(0, &statbuf->__unused4[1]);
-*/
- return err;
-}
-
asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
struct compat_timespec __user *interval)
{
@@ -557,57 +506,6 @@ sys32_delete_module(const char __user *name_user, unsigned int flags)
#endif /* CONFIG_MODULES */
-/* Translations due to time_t size differences. Which affects all
- sorts of things, like timeval and itimerval. */
-
-extern struct timezone sys_tz;
-
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
- long usec;
-
- if (!access_ok(VERIFY_READ, i, sizeof(*i)))
- return -EFAULT;
- if (__get_user(o->tv_sec, &i->tv_sec))
- return -EFAULT;
- if (__get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz)
-{
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_ts32(&kts, tv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf,
size_t count, u32 poshi, u32 poslo)
{
diff --git a/arch/s390/kernel/compat_linux.h b/arch/s390/kernel/compat_linux.h
index 05f8516366a..836a2884290 100644
--- a/arch/s390/kernel/compat_linux.h
+++ b/arch/s390/kernel/compat_linux.h
@@ -202,10 +202,6 @@ long sys32_execve(void);
long sys32_init_module(void __user *umod, unsigned long len,
const char __user *uargs);
long sys32_delete_module(const char __user *name_user, unsigned int flags);
-long sys32_gettimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz);
-long sys32_settimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz);
long sys32_pread64(unsigned int fd, char __user *ubuf, size_t count,
u32 poshi, u32 poslo);
long sys32_pwrite64(unsigned int fd, const char __user *ubuf,
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index ee51ca9e23b..fc2c97197a5 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -332,17 +332,17 @@ compat_sys_getrusage_wrapper:
llgtr %r3,%r3 # struct rusage_emu31 *
jg compat_sys_getrusage # branch to system call
- .globl sys32_gettimeofday_wrapper
-sys32_gettimeofday_wrapper:
+ .globl compat_sys_gettimeofday_wrapper
+compat_sys_gettimeofday_wrapper:
llgtr %r2,%r2 # struct timeval_emu31 *
llgtr %r3,%r3 # struct timezone *
- jg sys32_gettimeofday # branch to system call
+ jg compat_sys_gettimeofday # branch to system call
- .globl sys32_settimeofday_wrapper
-sys32_settimeofday_wrapper:
+ .globl compat_sys_settimeofday_wrapper
+compat_sys_settimeofday_wrapper:
llgtr %r2,%r2 # struct timeval_emu31 *
llgtr %r3,%r3 # struct timezone *
- jg sys32_settimeofday # branch to system call
+ jg compat_sys_settimeofday # branch to system call
.globl sys32_getgroups16_wrapper
sys32_getgroups16_wrapper:
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 3ae303914b4..2d61787949d 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -86,8 +86,8 @@ SYSCALL(sys_sethostname,sys_sethostname,sys32_sethostname_wrapper)
SYSCALL(sys_setrlimit,sys_setrlimit,compat_sys_setrlimit_wrapper) /* 75 */
SYSCALL(sys_old_getrlimit,sys_getrlimit,compat_sys_old_getrlimit_wrapper)
SYSCALL(sys_getrusage,sys_getrusage,compat_sys_getrusage_wrapper)
-SYSCALL(sys_gettimeofday,sys_gettimeofday,sys32_gettimeofday_wrapper)
-SYSCALL(sys_settimeofday,sys_settimeofday,sys32_settimeofday_wrapper)
+SYSCALL(sys_gettimeofday,sys_gettimeofday,compat_sys_gettimeofday_wrapper)
+SYSCALL(sys_settimeofday,sys_settimeofday,compat_sys_settimeofday_wrapper)
SYSCALL(sys_getgroups16,sys_ni_syscall,sys32_getgroups16_wrapper) /* 80 old getgroups16 syscall */
SYSCALL(sys_setgroups16,sys_ni_syscall,sys32_setgroups16_wrapper) /* old setgroups16 syscall */
NI_SYSCALL /* old select syscall */
diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c
index 2a37a6ca2a1..1cc1995531e 100644
--- a/arch/sparc64/kernel/iommu.c
+++ b/arch/sparc64/kernel/iommu.c
@@ -575,7 +575,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
}
/* Allocate iommu entries for that segment */
paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
- npages = iommu_num_pages(paddr, slen);
+ npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
entry = iommu_range_alloc(dev, iommu, npages, &handle);
/* Handle failure */
@@ -647,7 +647,8 @@ iommu_map_failed:
iopte_t *base;
vaddr = s->dma_address & IO_PAGE_MASK;
- npages = iommu_num_pages(s->dma_address, s->dma_length);
+ npages = iommu_num_pages(s->dma_address, s->dma_length,
+ IO_PAGE_SIZE);
iommu_range_free(iommu, vaddr, npages);
entry = (vaddr - iommu->page_table_map_base)
@@ -715,7 +716,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
if (!len)
break;
- npages = iommu_num_pages(dma_handle, len);
+ npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
iommu_range_free(iommu, dma_handle, npages);
entry = ((dma_handle - iommu->page_table_map_base)
diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h
index 53b19c8231a..591f5879039 100644
--- a/arch/sparc64/kernel/iommu_common.h
+++ b/arch/sparc64/kernel/iommu_common.h
@@ -35,17 +35,6 @@
#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
-static inline unsigned long iommu_num_pages(unsigned long vaddr,
- unsigned long slen)
-{
- unsigned long npages;
-
- npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK);
- npages >>= IO_PAGE_SHIFT;
-
- return npages;
-}
-
static inline int is_span_boundary(unsigned long entry,
unsigned long shift,
unsigned long boundary_size,
@@ -53,7 +42,8 @@ static inline int is_span_boundary(unsigned long entry,
struct scatterlist *sg)
{
unsigned long paddr = SG_ENT_PHYS_ADDRESS(outs);
- int nr = iommu_num_pages(paddr, outs->dma_length + sg->length);
+ int nr = iommu_num_pages(paddr, outs->dma_length + sg->length,
+ IO_PAGE_SIZE);
return iommu_is_span_boundary(entry, nr, shift, boundary_size);
}
diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c
index e86c73ec167..34a1fded394 100644
--- a/arch/sparc64/kernel/pci_sun4v.c
+++ b/arch/sparc64/kernel/pci_sun4v.c
@@ -384,7 +384,7 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist,
}
/* Allocate iommu entries for that segment */
paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
- npages = iommu_num_pages(paddr, slen);
+ npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
entry = iommu_range_alloc(dev, iommu, npages, &handle);
/* Handle failure */
@@ -461,7 +461,8 @@ iommu_map_failed:
unsigned long vaddr, npages;
vaddr = s->dma_address & IO_PAGE_MASK;
- npages = iommu_num_pages(s->dma_address, s->dma_length);
+ npages = iommu_num_pages(s->dma_address, s->dma_length,
+ IO_PAGE_SIZE);
iommu_range_free(iommu, vaddr, npages);
/* XXX demap? XXX */
s->dma_address = DMA_ERROR_CODE;
@@ -500,7 +501,7 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist,
if (!len)
break;
- npages = iommu_num_pages(dma_handle, len);
+ npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
iommu_range_free(iommu, dma_handle, npages);
entry = ((dma_handle - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 3320c9d0075..e800503879e 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -58,15 +58,6 @@
#include <asm/mmu_context.h>
#include <asm/compat_signal.h>
-/* 32-bit timeval and related flotsam. */
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
- return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
- (__put_user(i->tv_sec, &o->tv_sec) |
- __put_user(i->tv_usec, &o->tv_usec)));
-}
-
#ifdef CONFIG_SYSVIPC
asmlinkage long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, u32 fifth)
{
@@ -148,41 +139,6 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
return sys_ftruncate(fd, (high << 32) | low);
}
-int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
-{
- compat_ino_t ino;
- int err;
-
- if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
- !old_valid_dev(stat->rdev))
- return -EOVERFLOW;
-
- ino = stat->ino;
- if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
- return -EOVERFLOW;
-
- err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
- err |= put_user(stat->ino, &statbuf->st_ino);
- err |= put_user(stat->mode, &statbuf->st_mode);
- err |= put_user(stat->nlink, &statbuf->st_nlink);
- err |= put_user(high2lowuid(stat->uid), &statbuf->st_uid);
- err |= put_user(high2lowgid(stat->gid), &statbuf->st_gid);
- err |= put_user(old_encode_dev(stat->rdev), &statbuf->st_rdev);
- err |= put_user(stat->size, &statbuf->st_size);
- err |= put_user(stat->atime.tv_sec, &statbuf->st_atime);
- err |= put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec);
- err |= put_user(stat->mtime.tv_sec, &statbuf->st_mtime);
- err |= put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec);
- err |= put_user(stat->ctime.tv_sec, &statbuf->st_ctime);
- err |= put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec);
- err |= put_user(stat->blksize, &statbuf->st_blksize);
- err |= put_user(stat->blocks, &statbuf->st_blocks);
- err |= put_user(0, &statbuf->__unused4[0]);
- err |= put_user(0, &statbuf->__unused4[1]);
-
- return err;
-}
-
static int cp_compat_stat64(struct kstat *stat,
struct compat_stat64 __user *statbuf)
{
@@ -522,59 +478,6 @@ asmlinkage long sys32_delete_module(const char __user *name_user)
#endif /* CONFIG_MODULES */
-/* Translations due to time_t size differences. Which affects all
- sorts of things, like timeval and itimerval. */
-
-extern struct timezone sys_tz;
-
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
-{
- long usec;
-
- if (!access_ok(VERIFY_READ, i, sizeof(*i)))
- return -EFAULT;
- if (__get_user(o->tv_sec, &i->tv_sec))
- return -EFAULT;
- if (__get_user(usec, &i->tv_usec))
- return -EFAULT;
- o->tv_nsec = usec * 1000;
- return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
-{
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_ts32(&kts, tv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
asmlinkage compat_ssize_t sys32_pread64(unsigned int fd,
char __user *ubuf,
compat_size_t count,
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index 5daee4b04dd..b2fa4c16363 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -41,8 +41,8 @@ sys_call_table32:
/*100*/ .word sys32_getpriority, sys32_rt_sigreturn, sys32_rt_sigaction, sys32_rt_sigprocmask, sys32_rt_sigpending
.word compat_sys_rt_sigtimedwait, sys32_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
/*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
- .word sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
-/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys_fchown16, sys_fchmod
+ .word sys32_getgroups, compat_sys_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
+/*120*/ .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
.word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
/*130*/ .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
.word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
diff --git a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c
index 47e3acafb5b..365b6464e2c 100644
--- a/arch/sparc64/kernel/us3_cpufreq.c
+++ b/arch/sparc64/kernel/us3_cpufreq.c
@@ -183,7 +183,6 @@ static int __init us3_freq_cpu_init(struct cpufreq_policy *policy)
table[3].index = 0;
table[3].frequency = CPUFREQ_TABLE_END;
- policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
policy->cpuinfo.transition_latency = 0;
policy->cur = clock_tick;
diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c
index f5d7f4569ba..598711c62c8 100644
--- a/arch/um/kernel/exec.c
+++ b/arch/um/kernel/exec.c
@@ -42,23 +42,11 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
PT_REGS_SP(regs) = esp;
}
-#ifdef CONFIG_TTY_LOG
-extern void log_exec(char **argv, void *tty);
-#endif
-
static long execve1(char *file, char __user * __user *argv,
char __user *__user *env)
{
long error;
-#ifdef CONFIG_TTY_LOG
- struct tty_struct *tty;
- mutex_lock(&tty_mutex);
- tty = get_current_tty();
- if (tty)
- log_exec(argv, tty);
- mutex_unlock(&tty_mutex);
-#endif
error = do_execve(file, argv, env, &current->thread.regs);
if (error == 0) {
task_lock(current);
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index 8a48d6a3006..d66f0388f09 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -7,9 +7,6 @@ obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \
registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \
umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/
-obj-$(CONFIG_TTY_LOG) += tty_log.o
-user-objs-$(CONFIG_TTY_LOG) += tty_log.o
-
USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \
main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \
tty.o tls.o uaccess.o umid.o util.o
diff --git a/arch/um/os-Linux/tty_log.c b/arch/um/os-Linux/tty_log.c
deleted file mode 100644
index cc648e6fd3a..00000000000
--- a/arch/um/os-Linux/tty_log.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and
- * geoffrey hing <ghing@net.ohio-state.edu>
- * Licensed under the GPL
- */
-
-#include <errno.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include "init.h"
-#include "user.h"
-#include "os.h"
-
-#define TTY_LOG_DIR "./"
-
-/* Set early in boot and then unchanged */
-static char *tty_log_dir = TTY_LOG_DIR;
-static int tty_log_fd = -1;
-
-#define TTY_LOG_OPEN 1
-#define TTY_LOG_CLOSE 2
-#define TTY_LOG_WRITE 3
-#define TTY_LOG_EXEC 4
-
-#define TTY_READ 1
-#define TTY_WRITE 2
-
-struct tty_log_buf {
- int what;
- unsigned long tty;
- int len;
- int direction;
- unsigned long sec;
- unsigned long usec;
-};
-
-int open_tty_log(void *tty, void *current_tty)
-{
- struct timeval tv;
- struct tty_log_buf data;
- char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")];
- int fd;
-
- gettimeofday(&tv, NULL);
- if(tty_log_fd != -1){
- data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN,
- .tty = (unsigned long) tty,
- .len = sizeof(current_tty),
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- write(tty_log_fd, &data, sizeof(data));
- write(tty_log_fd, &current_tty, data.len);
- return tty_log_fd;
- }
-
- sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec,
- (unsigned int) tv.tv_usec);
-
- fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))),
- 0644);
- if(fd < 0){
- printk("open_tty_log : couldn't open '%s', errno = %d\n",
- buf, -fd);
- }
- return fd;
-}
-
-void close_tty_log(int fd, void *tty)
-{
- struct tty_log_buf data;
- struct timeval tv;
-
- if(tty_log_fd != -1){
- gettimeofday(&tv, NULL);
- data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE,
- .tty = (unsigned long) tty,
- .len = 0,
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- write(tty_log_fd, &data, sizeof(data));
- return;
- }
- os_close_file(fd);
-}
-
-static int log_chunk(int fd, const char *buf, int len)
-{
- int total = 0, try, missed, n;
- char chunk[64];
-
- while(len > 0){
- try = (len > sizeof(chunk)) ? sizeof(chunk) : len;
- missed = copy_from_user_proc(chunk, (char *) buf, try);
- try -= missed;
- n = write(fd, chunk, try);
- if(n != try) {
- if(n < 0)
- return -errno;
- return -EIO;
- }
- if(missed != 0)
- return -EFAULT;
-
- len -= try;
- total += try;
- buf += try;
- }
-
- return total;
-}
-
-int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read)
-{
- struct timeval tv;
- struct tty_log_buf data;
- int direction;
-
- if(fd == tty_log_fd){
- gettimeofday(&tv, NULL);
- direction = is_read ? TTY_READ : TTY_WRITE;
- data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE,
- .tty = (unsigned long) tty,
- .len = len,
- .direction = direction,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- write(tty_log_fd, &data, sizeof(data));
- }
-
- return log_chunk(fd, buf, len);
-}
-
-void log_exec(char **argv, void *tty)
-{
- struct timeval tv;
- struct tty_log_buf data;
- char **ptr,*arg;
- int len;
-
- if(tty_log_fd == -1) return;
-
- gettimeofday(&tv, NULL);
-
- len = 0;
- for(ptr = argv; ; ptr++){
- if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
- return;
- if(arg == NULL) break;
- len += strlen_user_proc(arg);
- }
-
- data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC,
- .tty = (unsigned long) tty,
- .len = len,
- .direction = 0,
- .sec = tv.tv_sec,
- .usec = tv.tv_usec } );
- write(tty_log_fd, &data, sizeof(data));
-
- for(ptr = argv; ; ptr++){
- if(copy_from_user_proc(&arg, ptr, sizeof(arg)))
- return;
- if(arg == NULL) break;
- log_chunk(tty_log_fd, arg, strlen_user_proc(arg));
- }
-}
-
-extern void register_tty_logger(int (*opener)(void *, void *),
- int (*writer)(int, const char *, int,
- void *, int),
- void (*closer)(int, void *));
-
-static int register_logger(void)
-{
- register_tty_logger(open_tty_log, write_tty_log, close_tty_log);
- return 0;
-}
-
-__uml_initcall(register_logger);
-
-static int __init set_tty_log_dir(char *name, int *add)
-{
- tty_log_dir = name;
- return 0;
-}
-
-__uml_setup("tty_log_dir=", set_tty_log_dir,
-"tty_log_dir=<directory>\n"
-" This is used to specify the directory where the logs of all pty\n"
-" data from this UML machine will be written.\n\n"
-);
-
-static int __init set_tty_log_fd(char *name, int *add)
-{
- char *end;
-
- tty_log_fd = strtoul(name, &end, 0);
- if((*end != '\0') || (end == name)){
- printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
- tty_log_fd = -1;
- }
-
- *add = 0;
- return 0;
-}
-
-__uml_setup("tty_log_fd=", set_tty_log_fd,
-"tty_log_fd=<fd>\n"
-" This is used to specify a preconfigured file descriptor to which all\n"
-" tty data will be written. Preconfigure the descriptor with something\n"
-" like '10>tty_log tty_log_fd=10'.\n\n"
-);
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f65c2744d57..7ccb6e60e60 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -39,10 +39,6 @@ config ARCH_DEFCONFIG
default "arch/x86/configs/i386_defconfig" if X86_32
default "arch/x86/configs/x86_64_defconfig" if X86_64
-
-config GENERIC_LOCKBREAK
- def_bool n
-
config GENERIC_TIME
def_bool y
@@ -95,7 +91,7 @@ config GENERIC_HWEIGHT
def_bool y
config GENERIC_GPIO
- def_bool n
+ bool
config ARCH_MAY_HAVE_PC_FDC
def_bool y
@@ -106,12 +102,6 @@ config RWSEM_GENERIC_SPINLOCK
config RWSEM_XCHGADD_ALGORITHM
def_bool X86_XADD
-config ARCH_HAS_ILOG2_U32
- def_bool n
-
-config ARCH_HAS_ILOG2_U64
- def_bool n
-
config ARCH_HAS_CPU_IDLE_WAIT
def_bool y
@@ -758,9 +748,8 @@ config I8K
Say N otherwise.
config X86_REBOOTFIXUPS
- def_bool n
- prompt "Enable X86 board specific fixups for reboot"
- depends on X86_32 && X86
+ bool "Enable X86 board specific fixups for reboot"
+ depends on X86_32
---help---
This enables chipset and/or board specific fixups to be done
in order to get reboot to work correctly. This is only needed on
@@ -944,8 +933,7 @@ config HIGHMEM
depends on X86_32 && (HIGHMEM64G || HIGHMEM4G)
config X86_PAE
- def_bool n
- prompt "PAE (Physical Address Extension) Support"
+ bool "PAE (Physical Address Extension) Support"
depends on X86_32 && !HIGHMEM4G
select RESOURCES_64BIT
help
@@ -1238,8 +1226,7 @@ config X86_PAT
If unsure, say Y.
config EFI
- def_bool n
- prompt "EFI runtime service support"
+ bool "EFI runtime service support"
depends on ACPI
---help---
This enables the kernel to use EFI runtime services that are
diff --git a/arch/x86/boot/video-vesa.c b/arch/x86/boot/video-vesa.c
index 1e6fe0214c8..99b3079dc6a 100644
--- a/arch/x86/boot/video-vesa.c
+++ b/arch/x86/boot/video-vesa.c
@@ -88,14 +88,11 @@ static int vesa_probe(void)
(vminfo.memory_layout == 4 ||
vminfo.memory_layout == 6) &&
vminfo.memory_planes == 1) {
-#ifdef CONFIG_FB
+#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
/* Graphics mode, color, linear frame buffer
supported. Only register the mode if
if framebuffer is configured, however,
- otherwise the user will be left without a screen.
- We don't require CONFIG_FB_VESA, however, since
- some of the other framebuffer drivers can use
- this mode-setting, too. */
+ otherwise the user will be left without a screen. */
mi = GET_HEAP(struct mode_info, 1);
mi->mode = mode + VIDEO_FIRST_VESA;
mi->depth = vminfo.bpp;
@@ -133,10 +130,12 @@ static int vesa_set_mode(struct mode_info *mode)
if ((vminfo.mode_attr & 0x15) == 0x05) {
/* It's a supported text mode */
is_graphic = 0;
+#ifdef CONFIG_FB_BOOT_VESA_SUPPORT
} else if ((vminfo.mode_attr & 0x99) == 0x99) {
/* It's a graphics mode with linear frame buffer */
is_graphic = 1;
vesa_mode |= 0x4000; /* Request linear frame buffer */
+#endif
} else {
return -1; /* Invalid mode */
}
diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index eb4314768bf..256b00b6189 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -571,8 +571,8 @@ ia32_sys_call_table:
.quad compat_sys_setrlimit /* 75 */
.quad compat_sys_old_getrlimit /* old_getrlimit */
.quad compat_sys_getrusage
- .quad sys32_gettimeofday
- .quad sys32_settimeofday
+ .quad compat_sys_gettimeofday
+ .quad compat_sys_settimeofday
.quad sys_getgroups16 /* 80 */
.quad sys_setgroups16
.quad sys32_old_select
diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c
index beda4232ce6..2e09dcd3c0a 100644
--- a/arch/x86/ia32/sys_ia32.c
+++ b/arch/x86/ia32/sys_ia32.c
@@ -49,41 +49,6 @@
#define AA(__x) ((unsigned long)(__x))
-int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
-{
- compat_ino_t ino;
-
- typeof(ubuf->st_uid) uid = 0;
- typeof(ubuf->st_gid) gid = 0;
- SET_UID(uid, kbuf->uid);
- SET_GID(gid, kbuf->gid);
- if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
- return -EOVERFLOW;
- if (kbuf->size >= 0x7fffffff)
- return -EOVERFLOW;
- ino = kbuf->ino;
- if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
- return -EOVERFLOW;
- if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
- __put_user(old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
- __put_user(ino, &ubuf->st_ino) ||
- __put_user(kbuf->mode, &ubuf->st_mode) ||
- __put_user(kbuf->nlink, &ubuf->st_nlink) ||
- __put_user(uid, &ubuf->st_uid) ||
- __put_user(gid, &ubuf->st_gid) ||
- __put_user(old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
- __put_user(kbuf->size, &ubuf->st_size) ||
- __put_user(kbuf->atime.tv_sec, &ubuf->st_atime) ||
- __put_user(kbuf->atime.tv_nsec, &ubuf->st_atime_nsec) ||
- __put_user(kbuf->mtime.tv_sec, &ubuf->st_mtime) ||
- __put_user(kbuf->mtime.tv_nsec, &ubuf->st_mtime_nsec) ||
- __put_user(kbuf->ctime.tv_sec, &ubuf->st_ctime) ||
- __put_user(kbuf->ctime.tv_nsec, &ubuf->st_ctime_nsec) ||
- __put_user(kbuf->blksize, &ubuf->st_blksize) ||
- __put_user(kbuf->blocks, &ubuf->st_blocks))
- return -EFAULT;
- return 0;
-}
asmlinkage long sys32_truncate64(char __user *filename,
unsigned long offset_low,
@@ -402,75 +367,11 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
return 0;
}
-static inline long get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
- int err = -EFAULT;
-
- if (access_ok(VERIFY_READ, i, sizeof(*i))) {
- err = __get_user(o->tv_sec, &i->tv_sec);
- err |= __get_user(o->tv_usec, &i->tv_usec);
- }
- return err;
-}
-
-static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
-{
- int err = -EFAULT;
-
- if (access_ok(VERIFY_WRITE, o, sizeof(*o))) {
- err = __put_user(i->tv_sec, &o->tv_sec);
- err |= __put_user(i->tv_usec, &o->tv_usec);
- }
- return err;
-}
-
asmlinkage long sys32_alarm(unsigned int seconds)
{
return alarm_setitimer(seconds);
}
-/*
- * Translations due to time_t size differences. Which affects all
- * sorts of things, like timeval and itimerval.
- */
-asmlinkage long sys32_gettimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
-{
- if (tv) {
- struct timeval ktv;
-
- do_gettimeofday(&ktv);
- if (put_tv32(tv, &ktv))
- return -EFAULT;
- }
- if (tz) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
- return -EFAULT;
- }
- return 0;
-}
-
-asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
- struct timezone __user *tz)
-{
- struct timeval ktv;
- struct timespec kts;
- struct timezone ktz;
-
- if (tv) {
- if (get_tv32(&ktv, tv))
- return -EFAULT;
- kts.tv_sec = ktv.tv_sec;
- kts.tv_nsec = ktv.tv_usec * NSEC_PER_USEC;
- }
- if (tz) {
- if (copy_from_user(&ktz, tz, sizeof(ktz)))
- return -EFAULT;
- }
-
- return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
-}
-
struct sel_arg_struct {
unsigned int n;
unsigned int inp;
diff --git a/arch/x86/kernel/amd_iommu.c b/arch/x86/kernel/amd_iommu.c
index 34e4d112b1e..a8fd9ebdc8e 100644
--- a/arch/x86/kernel/amd_iommu.c
+++ b/arch/x86/kernel/amd_iommu.c
@@ -295,7 +295,7 @@ static int iommu_flush_pages(struct amd_iommu *iommu, u16 domid,
u64 address, size_t size)
{
int s = 0;
- unsigned pages = iommu_num_pages(address, size);
+ unsigned pages = iommu_num_pages(address, size, PAGE_SIZE);
address &= PAGE_MASK;
@@ -680,7 +680,8 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
iommu->exclusion_start < dma_dom->aperture_size) {
unsigned long startpage = iommu->exclusion_start >> PAGE_SHIFT;
int pages = iommu_num_pages(iommu->exclusion_start,
- iommu->exclusion_length);
+ iommu->exclusion_length,
+ PAGE_SIZE);
dma_ops_reserve_addresses(dma_dom, startpage, pages);
}
@@ -935,7 +936,7 @@ static dma_addr_t __map_single(struct device *dev,
unsigned long align_mask = 0;
int i;
- pages = iommu_num_pages(paddr, size);
+ pages = iommu_num_pages(paddr, size, PAGE_SIZE);
paddr &= PAGE_MASK;
if (align)
@@ -980,7 +981,7 @@ static void __unmap_single(struct amd_iommu *iommu,
if ((dma_addr == 0) || (dma_addr + size > dma_dom->aperture_size))
return;
- pages = iommu_num_pages(dma_addr, size);
+ pages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
dma_addr &= PAGE_MASK;
start = dma_addr;
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 080d1d27f37..e1e731d78f3 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -217,16 +217,6 @@ static inline unsigned long verify_bit_range(unsigned long* bitmap,
#endif /* CONFIG_IOMMU_DEBUG */
-static inline unsigned int num_dma_pages(unsigned long dma, unsigned int dmalen)
-{
- unsigned int npages;
-
- npages = PAGE_ALIGN(dma + dmalen) - (dma & PAGE_MASK);
- npages >>= PAGE_SHIFT;
-
- return npages;
-}
-
static inline int translation_enabled(struct iommu_table *tbl)
{
/* only PHBs with translation enabled have an IOMMU table */
@@ -408,7 +398,7 @@ static void calgary_unmap_sg(struct device *dev,
if (dmalen == 0)
break;
- npages = num_dma_pages(dma, dmalen);
+ npages = iommu_num_pages(dma, dmalen, PAGE_SIZE);
iommu_free(tbl, dma, npages);
}
}
@@ -427,7 +417,7 @@ static int calgary_map_sg(struct device *dev, struct scatterlist *sg,
BUG_ON(!sg_page(s));
vaddr = (unsigned long) sg_virt(s);
- npages = num_dma_pages(vaddr, s->length);
+ npages = iommu_num_pages(vaddr, s->length, PAGE_SIZE);
entry = iommu_range_alloc(dev, tbl, npages);
if (entry == bad_dma_address) {
@@ -464,7 +454,7 @@ static dma_addr_t calgary_map_single(struct device *dev, phys_addr_t paddr,
struct iommu_table *tbl = find_iommu_table(dev);
uaddr = (unsigned long)vaddr;
- npages = num_dma_pages(uaddr, size);
+ npages = iommu_num_pages(uaddr, size, PAGE_SIZE);
return iommu_alloc(dev, tbl, vaddr, npages, direction);
}
@@ -475,7 +465,7 @@ static void calgary_unmap_single(struct device *dev, dma_addr_t dma_handle,
struct iommu_table *tbl = find_iommu_table(dev);
unsigned int npages;
- npages = num_dma_pages(dma_handle, size);
+ npages = iommu_num_pages(dma_handle, size, PAGE_SIZE);
iommu_free(tbl, dma_handle, npages);
}
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 0a3824e837b..19262482021 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -125,13 +125,13 @@ void __init pci_iommu_alloc(void)
pci_swiotlb_init();
}
-unsigned long iommu_num_pages(unsigned long addr, unsigned long len)
+unsigned long iommu_nr_pages(unsigned long addr, unsigned long len)
{
unsigned long size = roundup((addr & ~PAGE_MASK) + len, PAGE_SIZE);
return size >> PAGE_SHIFT;
}
-EXPORT_SYMBOL(iommu_num_pages);
+EXPORT_SYMBOL(iommu_nr_pages);
#endif
void *dma_generic_alloc_coherent(struct device *dev, size_t size,
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index 145f1c83369..e3f75bbcede 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -231,7 +231,7 @@ nonforced_iommu(struct device *dev, unsigned long addr, size_t size)
static dma_addr_t dma_map_area(struct device *dev, dma_addr_t phys_mem,
size_t size, int dir, unsigned long align_mask)
{
- unsigned long npages = iommu_num_pages(phys_mem, size);
+ unsigned long npages = iommu_num_pages(phys_mem, size, PAGE_SIZE);
unsigned long iommu_page = alloc_iommu(dev, npages, align_mask);
int i;
@@ -285,7 +285,7 @@ static void gart_unmap_single(struct device *dev, dma_addr_t dma_addr,
return;
iommu_page = (dma_addr - iommu_bus_base)>>PAGE_SHIFT;
- npages = iommu_num_pages(dma_addr, size);
+ npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
for (i = 0; i < npages; i++) {
iommu_gatt_base[iommu_page + i] = gart_unmapped_entry;
CLEAR_LEAK(iommu_page + i);
@@ -368,7 +368,7 @@ static int __dma_map_cont(struct device *dev, struct scatterlist *start,
}
addr = phys_addr;
- pages = iommu_num_pages(s->offset, s->length);
+ pages = iommu_num_pages(s->offset, s->length, PAGE_SIZE);
while (pages--) {
iommu_gatt_base[iommu_page] = GPTE_ENCODE(addr);
SET_LEAK(iommu_page);
@@ -451,7 +451,7 @@ gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
seg_size += s->length;
need = nextneed;
- pages += iommu_num_pages(s->offset, s->length);
+ pages += iommu_num_pages(s->offset, s->length, PAGE_SIZE);
ps = s;
}
if (dma_map_cont(dev, start_sg, i - start, sgmap, pages, need) < 0)
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 05191bbc68b..0a23b5795b2 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -223,11 +223,25 @@ static struct platform_device rtc_device = {
static __init int add_rtc_cmos(void)
{
#ifdef CONFIG_PNP
- if (!pnp_platform_devices)
- platform_device_register(&rtc_device);
-#else
+ static const char *ids[] __initconst =
+ { "PNP0b00", "PNP0b01", "PNP0b02", };
+ struct pnp_dev *dev;
+ struct pnp_id *id;
+ int i;
+
+ pnp_for_each_dev(dev) {
+ for (id = dev->id; id; id = id->next) {
+ for (i = 0; i < ARRAY_SIZE(ids); i++) {
+ if (compare_pnp_id(id, ids[i]) != 0)
+ return 0;
+ }
+ }
+ }
+#endif
+
platform_device_register(&rtc_device);
-#endif /* CONFIG_PNP */
+ dev_info(&rtc_device.dev,
+ "registered platform RTC device (no PNP device found)\n");
return 0;
}
device_initcall(add_rtc_cmos);
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 8c3aca7cb34..7ed9e070a6e 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -282,6 +282,8 @@ static void __cpuinit smp_callin(void)
cpu_set(cpuid, cpu_callin_map);
}
+static int __cpuinitdata unsafe_smp;
+
/*
* Activate a secondary processor.
*/
@@ -397,7 +399,7 @@ static void __cpuinit smp_apply_quirks(struct cpuinfo_x86 *c)
goto valid_k7;
/* If we get here, not a certified SMP capable AMD system. */
- add_taint(TAINT_UNSAFE_SMP);
+ unsafe_smp = 1;
}
valid_k7:
@@ -414,12 +416,10 @@ static void __cpuinit smp_checks(void)
* Don't taint if we are running SMP kernel on a single non-MP
* approved Athlon
*/
- if (tainted & TAINT_UNSAFE_SMP) {
- if (num_online_cpus())
- printk(KERN_INFO "WARNING: This combination of AMD"
- "processors is not suitable for SMP.\n");
- else
- tainted &= ~TAINT_UNSAFE_SMP;
+ if (unsafe_smp && num_online_cpus() > 1) {
+ printk(KERN_INFO "WARNING: This combination of AMD"
+ "processors is not suitable for SMP.\n");
+ add_taint(TAINT_UNSAFE_SMP);
}
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0d682fc6aeb..19afbb644c7 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -564,7 +564,7 @@ static void kvm_set_time_scale(uint32_t tsc_khz, struct pvclock_vcpu_time_info *
hv_clock->tsc_to_system_mul = div_frac(nsecs, tps32);
pr_debug("%s: tsc_khz %u, tsc_shift %d, tsc_mul %u\n",
- __FUNCTION__, tsc_khz, hv_clock->tsc_shift,
+ __func__, tsc_khz, hv_clock->tsc_shift,
hv_clock->tsc_to_system_mul);
}
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 3c578ef78c4..24649ada08d 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -260,115 +260,3 @@ static int __init init_acpi_device_notify(void)
}
arch_initcall(init_acpi_device_notify);
-
-
-#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
-
-#ifdef CONFIG_PM
-static u32 rtc_handler(void *context)
-{
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_disable_event(ACPI_EVENT_RTC, 0);
- return ACPI_INTERRUPT_HANDLED;
-}
-
-static inline void rtc_wake_setup(void)
-{
- acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
- /*
- * After the RTC handler is installed, the Fixed_RTC event should
- * be disabled. Only when the RTC alarm is set will it be enabled.
- */
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_on(struct device *dev)
-{
- acpi_clear_event(ACPI_EVENT_RTC);
- acpi_enable_event(ACPI_EVENT_RTC, 0);
-}
-
-static void rtc_wake_off(struct device *dev)
-{
- acpi_disable_event(ACPI_EVENT_RTC, 0);
-}
-#else
-#define rtc_wake_setup() do{}while(0)
-#define rtc_wake_on NULL
-#define rtc_wake_off NULL
-#endif
-
-/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
- * its device node and pass extra config data. This helps its driver use
- * capabilities that the now-obsolete mc146818 didn't have, and informs it
- * that this board's RTC is wakeup-capable (per ACPI spec).
- */
-#include <linux/mc146818rtc.h>
-
-static struct cmos_rtc_board_info rtc_info;
-
-
-/* PNP devices are registered in a subsys_initcall();
- * ACPI specifies the PNP IDs to use.
- */
-#include <linux/pnp.h>
-
-static int __init pnp_match(struct device *dev, void *data)
-{
- static const char *ids[] = { "PNP0b00", "PNP0b01", "PNP0b02", };
- struct pnp_dev *pnp = to_pnp_dev(dev);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ids); i++) {
- if (compare_pnp_id(pnp->id, ids[i]) != 0)
- return 1;
- }
- return 0;
-}
-
-static struct device *__init get_rtc_dev(void)
-{
- return bus_find_device(&pnp_bus_type, NULL, NULL, pnp_match);
-}
-
-static int __init acpi_rtc_init(void)
-{
- struct device *dev = get_rtc_dev();
-
- if (acpi_disabled)
- return 0;
-
- if (dev) {
- rtc_wake_setup();
- rtc_info.wake_on = rtc_wake_on;
- rtc_info.wake_off = rtc_wake_off;
-
- /* workaround bug in some ACPI tables */
- if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
- DBG("bogus FADT month_alarm\n");
- acpi_gbl_FADT.month_alarm = 0;
- }
-
- rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
- rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
- rtc_info.rtc_century = acpi_gbl_FADT.century;
-
- /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
- if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
- printk(PREFIX "RTC can wake from S4\n");
-
-
- dev->platform_data = &rtc_info;
-
- /* RTC always wakes from S1/S2/S3, and often S4/STD */
- device_init_wakeup(dev, 1);
-
- put_device(dev);
- } else
- DBG("RTC unavailable?\n");
- return 0;
-}
-module_init(acpi_rtc_init);
-
-#endif
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index 408da30594c..1f18ad9e4fe 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct of_device *ofdev,
ret = of_irq_to_resource(dn, 0, &irq_res);
if (ret == NO_IRQ)
- irq_res.start = irq_res.end = -1;
+ irq_res.start = irq_res.end = 0;
else
irq_res.flags = 0;
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index 6318f6b5736..d8e8c49c0cb 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -54,7 +54,7 @@ config FIRMWARE_IN_KERNEL
such firmware, and do not wish to use an initrd.
This single option controls the inclusion of firmware for
- every driver which usees request_firmare() and ships its
+ every driver which uses request_firmare() and ships its
firmware in the kernel source tree, to avoid a proliferation
of 'Include firmware for xxx device' options.
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index c9c92b00fd5..b7e571031ec 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -164,8 +164,7 @@ static ssize_t firmware_loading_store(struct device *dev,
}
/* fallthrough */
default:
- printk(KERN_ERR "%s: unexpected value (%d)\n", __func__,
- loading);
+ dev_err(dev, "%s: unexpected value (%d)\n", __func__, loading);
/* fallthrough */
case -1:
fw_load_abort(fw_priv);
@@ -309,7 +308,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
*dev_p = NULL;
if (!fw_priv || !f_dev) {
- printk(KERN_ERR "%s: kmalloc failed\n", __func__);
+ dev_err(device, "%s: kmalloc failed\n", __func__);
retval = -ENOMEM;
goto error_kfree;
}
@@ -329,8 +328,7 @@ static int fw_register_device(struct device **dev_p, const char *fw_name,
f_dev->uevent_suppress = 1;
retval = device_register(f_dev);
if (retval) {
- printk(KERN_ERR "%s: device_register failed\n",
- __func__);
+ dev_err(device, "%s: device_register failed\n", __func__);
goto error_kfree;
}
*dev_p = f_dev;
@@ -363,15 +361,13 @@ static int fw_setup_device(struct firmware *fw, struct device **dev_p,
fw_priv->fw = fw;
retval = sysfs_create_bin_file(&f_dev->kobj, &fw_priv->attr_data);
if (retval) {
- printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
- __func__);
+ dev_err(device, "%s: sysfs_create_bin_file failed\n", __func__);
goto error_unreg;
}
retval = device_create_file(f_dev, &dev_attr_loading);
if (retval) {
- printk(KERN_ERR "%s: device_create_file failed\n",
- __func__);
+ dev_err(device, "%s: device_create_file failed\n", __func__);
goto error_unreg;
}
@@ -401,8 +397,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
- printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
- __func__);
+ dev_err(device, "%s: kmalloc(struct firmware) failed\n",
+ __func__);
retval = -ENOMEM;
goto out;
}
@@ -411,15 +407,15 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
builtin++) {
if (strcmp(name, builtin->name))
continue;
- printk(KERN_INFO "firmware: using built-in firmware %s\n",
- name);
+ dev_info(device, "firmware: using built-in firmware %s\n",
+ name);
firmware->size = builtin->size;
firmware->data = builtin->data;
return 0;
}
if (uevent)
- printk(KERN_INFO "firmware: requesting %s\n", name);
+ dev_info(device, "firmware: requesting %s\n", name);
retval = fw_setup_device(firmware, &f_dev, name, device, uevent);
if (retval)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 3f940393d6c..66b710c2881 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -42,10 +42,8 @@ struct resource *platform_get_resource(struct platform_device *dev,
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
- if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
- IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
- if (num-- == 0)
- return r;
+ if (type == resource_type(r) && num-- == 0)
+ return r;
}
return NULL;
}
@@ -78,10 +76,8 @@ struct resource *platform_get_resource_byname(struct platform_device *dev,
for (i = 0; i < dev->num_resources; i++) {
struct resource *r = &dev->resource[i];
- if ((r->flags & (IORESOURCE_IO|IORESOURCE_MEM|
- IORESOURCE_IRQ|IORESOURCE_DMA)) == type)
- if (!strcmp(r->name, name))
- return r;
+ if (type == resource_type(r) && !strcmp(r->name, name))
+ return r;
}
return NULL;
}
@@ -259,9 +255,9 @@ int platform_device_add(struct platform_device *pdev)
p = r->parent;
if (!p) {
- if (r->flags & IORESOURCE_MEM)
+ if (resource_type(r) == IORESOURCE_MEM)
p = &iomem_resource;
- else if (r->flags & IORESOURCE_IO)
+ else if (resource_type(r) == IORESOURCE_IO)
p = &ioport_resource;
}
@@ -282,9 +278,14 @@ int platform_device_add(struct platform_device *pdev)
return ret;
failed:
- while (--i >= 0)
- if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
- release_resource(&pdev->resource[i]);
+ while (--i >= 0) {
+ struct resource *r = &pdev->resource[i];
+ unsigned long type = resource_type(r);
+
+ if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
+ release_resource(r);
+ }
+
return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);
@@ -306,7 +307,9 @@ void platform_device_del(struct platform_device *pdev)
for (i = 0; i < pdev->num_resources; i++) {
struct resource *r = &pdev->resource[i];
- if (r->flags & (IORESOURCE_MEM|IORESOURCE_IO))
+ unsigned long type = resource_type(r);
+
+ if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
release_resource(r);
}
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 273a944d404..03bde7524bc 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -778,10 +778,7 @@ EXPORT_SYMBOL_GPL(device_suspend);
void __suspend_report_result(const char *function, void *fn, int ret)
{
- if (ret) {
- printk(KERN_ERR "%s(): ", function);
- print_fn_descriptor_symbol("%s returns ", fn);
- printk("%d\n", ret);
- }
+ if (ret)
+ printk(KERN_ERR "%s(): %pF returns %d\n", function, fn, ret);
}
EXPORT_SYMBOL_GPL(__suspend_report_result);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 49f274197b1..432cf401829 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1882,10 +1882,6 @@ static int __init atari_floppy_init (void)
/* Amiga, Mac, ... don't have Atari-compatible floppy :-) */
return -ENODEV;
- if (MACH_IS_HADES)
- /* Hades doesn't have Atari-compatible floppy */
- return -ENODEV;
-
if (register_blkdev(FLOPPY_MAJOR,"fd"))
return -EBUSY;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index cf64ddf5d83..2cea27aba9a 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4172,7 +4172,7 @@ static int __init floppy_init(void)
int i, unit, drive;
int err, dr;
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
if (check_legacy_ioport(FDC1))
return -ENODEV;
#endif
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c
index f1c8feb5510..1730d29e604 100644
--- a/drivers/block/viodasd.c
+++ b/drivers/block/viodasd.c
@@ -249,7 +249,6 @@ static int send_request(struct request *req)
struct HvLpEvent *hev;
struct scatterlist sg[VIOMAXBLOCKDMA];
int sgindex;
- int statindex;
struct viodasd_device *d;
unsigned long flags;
@@ -258,11 +257,9 @@ static int send_request(struct request *req)
if (rq_data_dir(req) == READ) {
direction = DMA_FROM_DEVICE;
viocmd = viomajorsubtype_blockio | vioblockread;
- statindex = 0;
} else {
direction = DMA_TO_DEVICE;
viocmd = viomajorsubtype_blockio | vioblockwrite;
- statindex = 1;
}
d = req->rq_disk->private_data;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 700ff967945..122254155ae 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -1043,15 +1043,6 @@ config HPET
open selects one of the timers supported by the HPET. The timers are
non-periodic and/or periodic.
-config HPET_RTC_IRQ
- bool
- default HPET_EMULATE_RTC
- depends on RTC && HPET
- help
- If you say Y here, you will disable RTC_IRQ in drivers/char/rtc.c. It
- is assumed the platform called hpet_alloc with the RTC IRQ values for
- the HPET timers.
-
config HPET_MMAP
bool "Allow mmap of HPET"
default y
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index b899d9182c7..05674febb0c 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -478,7 +478,7 @@ static int do_ac_read(int IndexCard, char __user *buf,
struct st_ram_io *st_loc, struct mailbox *mailbox)
{
void __iomem *from = apbs[IndexCard].RamIO + RAM_TO_PC;
- unsigned char *to = (unsigned char *)&mailbox;
+ unsigned char *to = (unsigned char *)mailbox;
#ifdef DEBUG
int c;
#endif
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index fb584938c9c..5329d482b58 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -443,7 +443,6 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
{
unsigned char save_control;
unsigned long flags;
- unsigned long uip_watchdog = jiffies;
/*
* read RTC once any update in progress is done. The update
@@ -456,8 +455,7 @@ static void ds1286_get_time(struct rtc_time *rtc_tm)
*/
if (ds1286_is_updating() != 0)
- while (time_before(jiffies, uip_watchdog + 2*HZ/100))
- barrier();
+ msleep(20);
/*
* Only the values that we read from the RTC are set. We leave
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index ec7aded0a2d..bf70450a49c 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -367,13 +367,13 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
spin_lock_irqsave(&hp->lock, flags);
if (--hp->count == 0) {
- if (hp->ops->notifier_del)
- hp->ops->notifier_del(hp, hp->data);
-
/* We are done with the tty pointer now. */
hp->tty = NULL;
spin_unlock_irqrestore(&hp->lock, flags);
+ if (hp->ops->notifier_del)
+ hp->ops->notifier_del(hp, hp->data);
+
/*
* Chain calls chars_in_buffer() and returns immediately if
* there is no buffered data otherwise sleeps on a wait queue
@@ -416,11 +416,11 @@ static void hvc_hangup(struct tty_struct *tty)
hp->n_outbuf = 0;
hp->tty = NULL;
+ spin_unlock_irqrestore(&hp->lock, flags);
+
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
- spin_unlock_irqrestore(&hp->lock, flags);
-
while(temp_open_count) {
--temp_open_count;
kref_put(&hp->kref, destroy_hvc_struct);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 8e8afb6141f..3123bf57ad9 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2695,7 +2695,7 @@ static __devinit void default_find_bmc(void)
for (i = 0; ; i++) {
if (!ipmi_defaults[i].port)
break;
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (check_legacy_ioport(ipmi_defaults[i].port))
continue;
#endif
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 5df4003ad87..12d327a2c9b 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -513,7 +513,7 @@ static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
size_t len)
{
void __iomem *baseAddr = brd->basemem;
- const u16 *uptr = ptr;
+ const __le16 *uptr = ptr;
size_t wlen, len2, j;
unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
unsigned int i, retry;
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 6af435b8986..c8752eaad48 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1205,7 +1205,7 @@ static int proc_do_uuid(ctl_table *table, int write, struct file *filp,
return proc_dostring(&fake_table, write, filp, buffer, lenp, ppos);
}
-static int uuid_strategy(ctl_table *table, int __user *name, int nlen,
+static int uuid_strategy(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index b47710c1788..17683de9571 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -96,7 +96,7 @@ static unsigned long rtc_port;
static int rtc_irq;
#endif
-#ifdef CONFIG_HPET_RTC_IRQ
+#ifdef CONFIG_HPET_EMULATE_RTC
#undef RTC_IRQ
#endif
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 8fdfe9c871e..dce4cc0e695 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -23,6 +23,7 @@
#include <linux/reboot.h>
#include <linux/sysrq.h>
#include <linux/kbd_kern.h>
+#include <linux/proc_fs.h>
#include <linux/quotaops.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -326,6 +327,7 @@ static struct sysrq_key_op sysrq_moom_op = {
.handler = sysrq_handle_moom,
.help_msg = "Full",
.action_msg = "Manual OOM execution",
+ .enable_mask = SYSRQ_ENABLE_SIGNAL,
};
static void sysrq_handle_kill(int key, struct tty_struct *tty)
@@ -533,3 +535,32 @@ int unregister_sysrq_key(int key, struct sysrq_key_op *op_p)
return __sysrq_swap_key_ops(key, NULL, op_p);
}
EXPORT_SYMBOL(unregister_sysrq_key);
+
+#ifdef CONFIG_PROC_FS
+/*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ if (count) {
+ char c;
+
+ if (get_user(c, buf))
+ return -EFAULT;
+ __handle_sysrq(c, NULL, 0);
+ }
+ return count;
+}
+
+static const struct file_operations proc_sysrq_trigger_operations = {
+ .write = write_sysrq_trigger,
+};
+
+static int __init sysrq_init(void)
+{
+ proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
+ return 0;
+}
+module_init(sysrq_init);
+#endif
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 1fee7034a38..e70d13defde 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -525,19 +525,19 @@ void tpm_get_timeouts(struct tpm_chip *chip)
timeout =
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_1_IDX)));
if (timeout)
- chip->vendor.timeout_a = msecs_to_jiffies(timeout);
+ chip->vendor.timeout_a = usecs_to_jiffies(timeout);
timeout =
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_2_IDX)));
if (timeout)
- chip->vendor.timeout_b = msecs_to_jiffies(timeout);
+ chip->vendor.timeout_b = usecs_to_jiffies(timeout);
timeout =
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_3_IDX)));
if (timeout)
- chip->vendor.timeout_c = msecs_to_jiffies(timeout);
+ chip->vendor.timeout_c = usecs_to_jiffies(timeout);
timeout =
be32_to_cpu(*((__be32 *) (data + TPM_GET_CAP_RET_UINT32_4_IDX)));
if (timeout)
- chip->vendor.timeout_d = msecs_to_jiffies(timeout);
+ chip->vendor.timeout_d = usecs_to_jiffies(timeout);
duration:
memcpy(data, tpm_cap, sizeof(tpm_cap));
@@ -554,15 +554,22 @@ duration:
return;
chip->vendor.duration[TPM_SHORT] =
- msecs_to_jiffies(be32_to_cpu
+ usecs_to_jiffies(be32_to_cpu
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_1_IDX))));
+ /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above
+ * value wrong and apparently reports msecs rather than usecs. So we
+ * fix up the resulting too-small TPM_SHORT value to make things work.
+ */
+ if (chip->vendor.duration[TPM_SHORT] < (HZ/100))
+ chip->vendor.duration[TPM_SHORT] = HZ;
+
chip->vendor.duration[TPM_MEDIUM] =
- msecs_to_jiffies(be32_to_cpu
+ usecs_to_jiffies(be32_to_cpu
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_2_IDX))));
chip->vendor.duration[TPM_LONG] =
- msecs_to_jiffies(be32_to_cpu
+ usecs_to_jiffies(be32_to_cpu
(*((__be32 *) (data +
TPM_GET_CAP_RET_UINT32_3_IDX))));
}
@@ -1180,11 +1187,8 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
- if (chip == NULL || devname == NULL) {
- kfree(chip);
- kfree(devname);
- return NULL;
- }
+ if (chip == NULL || devname == NULL)
+ goto out_free;
mutex_init(&chip->buffer_mutex);
mutex_init(&chip->tpm_mutex);
@@ -1201,8 +1205,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
if (chip->dev_num >= TPM_NUM_DEVICES) {
dev_err(dev, "No available tpm device numbers\n");
- kfree(chip);
- return NULL;
+ goto out_free;
} else if (chip->dev_num == 0)
chip->vendor.miscdev.minor = TPM_MINOR;
else
@@ -1243,6 +1246,11 @@ struct tpm_chip *tpm_register_hardware(struct device *dev,
spin_unlock(&driver_lock);
return chip;
+
+out_free:
+ kfree(chip);
+ kfree(devname);
+ return NULL;
}
EXPORT_SYMBOL_GPL(tpm_register_hardware);
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 7053d633369..3f48d88cffc 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3032,11 +3032,12 @@ EXPORT_SYMBOL(tty_devnum);
void proc_clear_tty(struct task_struct *p)
{
+ unsigned long flags;
struct tty_struct *tty;
- spin_lock_irq(&p->sighand->siglock);
+ spin_lock_irqsave(&p->sighand->siglock, flags);
tty = p->signal->tty;
p->signal->tty = NULL;
- spin_unlock_irq(&p->sighand->siglock);
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
tty_kref_put(tty);
}
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index 57029fefd64..d8f83e26e4a 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -59,7 +59,7 @@
* by Martin Mares <mj@atrey.karlin.mff.cuni.cz>, July 1998
*
* Removed old-style timers, introduced console_timer, made timer
- * deletion SMP-safe. 17Jun00, Andrew Morton <andrewm@uow.edu.au>
+ * deletion SMP-safe. 17Jun00, Andrew Morton
*
* Removed console_lock, enabled interrupts across all console operations
* 13 March 2001, Andrew Morton
@@ -301,7 +301,7 @@ static void scrup(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
+ scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
vc->vc_size_row * nr);
}
@@ -319,7 +319,7 @@ static void scrdown(struct vc_data *vc, unsigned int t, unsigned int b, int nr)
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
+ scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
}
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -434,7 +434,6 @@ static void update_attr(struct vc_data *vc)
vc->vc_blink, vc->vc_underline,
vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
- vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, vc->vc_decscnm, false) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 4a16b5b61cf..f0d9b415db5 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -119,6 +119,7 @@
#define FERR_NF_UNCORRECTABLE (FERR_NF_M12ERR | \
FERR_NF_M11ERR | \
FERR_NF_M10ERR | \
+ FERR_NF_M9ERR | \
FERR_NF_M8ERR | \
FERR_NF_M7ERR | \
FERR_NF_M6ERR | \
@@ -301,6 +302,9 @@ static char *numcol_toString[] = {
};
#endif
+/* enables the report of miscellaneous messages as CE errors - default off */
+static int misc_messages;
+
/* Enumeration of supported devices */
enum i5000_chips {
I5000P = 0,
@@ -466,7 +470,8 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
struct i5000_error_info *info,
int handle_errors)
{
- char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ char msg[EDAC_MC_LABEL_LEN + 1 + 160];
+ char *specific = NULL;
u32 allErrors;
int branch;
int channel;
@@ -480,11 +485,6 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
if (!allErrors)
return; /* if no error, return now */
- /* ONLY ONE of the possible error bits will be set, as per the docs */
- i5000_mc_printk(mci, KERN_ERR,
- "FATAL ERRORS Found!!! 1st FATAL Err Reg= 0x%x\n",
- allErrors);
-
branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
channel = branch;
@@ -501,28 +501,42 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
rdwr ? "Write" : "Read", ras, cas);
/* Only 1 bit will be on */
- if (allErrors & FERR_FAT_M1ERR) {
- i5000_mc_printk(mci, KERN_ERR,
- "Alert on non-redundant retry or fast "
- "reset timeout\n");
-
- } else if (allErrors & FERR_FAT_M2ERR) {
- i5000_mc_printk(mci, KERN_ERR,
- "Northbound CRC error on non-redundant "
- "retry\n");
-
- } else if (allErrors & FERR_FAT_M3ERR) {
- i5000_mc_printk(mci, KERN_ERR,
- ">Tmid Thermal event with intelligent "
- "throttling disabled\n");
+ switch (allErrors) {
+ case FERR_FAT_M1ERR:
+ specific = "Alert on non-redundant retry or fast "
+ "reset timeout";
+ break;
+ case FERR_FAT_M2ERR:
+ specific = "Northbound CRC error on non-redundant "
+ "retry";
+ break;
+ case FERR_FAT_M3ERR:
+ {
+ static int done;
+
+ /*
+ * This error is generated to inform that the intelligent
+ * throttling is disabled and the temperature passed the
+ * specified middle point. Since this is something the BIOS
+ * should take care of, we'll warn only once to avoid
+ * worthlessly flooding the log.
+ */
+ if (done)
+ return;
+ done++;
+
+ specific = ">Tmid Thermal event with intelligent "
+ "throttling disabled";
+ }
+ break;
}
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
- "FATAL Err=0x%x)",
+ "FATAL Err=0x%x (%s))",
branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
- allErrors);
+ allErrors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
@@ -539,7 +553,8 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
struct i5000_error_info *info,
int handle_errors)
{
- char msg[EDAC_MC_LABEL_LEN + 1 + 90];
+ char msg[EDAC_MC_LABEL_LEN + 1 + 170];
+ char *specific = NULL;
u32 allErrors;
u32 ue_errors;
u32 ce_errors;
@@ -557,10 +572,6 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
return; /* if no error, return now */
/* ONLY ONE of the possible error bits will be set, as per the docs */
- i5000_mc_printk(mci, KERN_WARNING,
- "NON-FATAL ERRORS Found!!! 1st NON-FATAL Err "
- "Reg= 0x%x\n", allErrors);
-
ue_errors = allErrors & FERR_NF_UNCORRECTABLE;
if (ue_errors) {
debugf0("\tUncorrected bits= 0x%x\n", ue_errors);
@@ -579,12 +590,47 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
rank, channel, channel + 1, branch >> 1, bank,
rdwr ? "Write" : "Read", ras, cas);
+ switch (ue_errors) {
+ case FERR_NF_M12ERR:
+ specific = "Non-Aliased Uncorrectable Patrol Data ECC";
+ break;
+ case FERR_NF_M11ERR:
+ specific = "Non-Aliased Uncorrectable Spare-Copy "
+ "Data ECC";
+ break;
+ case FERR_NF_M10ERR:
+ specific = "Non-Aliased Uncorrectable Mirrored Demand "
+ "Data ECC";
+ break;
+ case FERR_NF_M9ERR:
+ specific = "Non-Aliased Uncorrectable Non-Mirrored "
+ "Demand Data ECC";
+ break;
+ case FERR_NF_M8ERR:
+ specific = "Aliased Uncorrectable Patrol Data ECC";
+ break;
+ case FERR_NF_M7ERR:
+ specific = "Aliased Uncorrectable Spare-Copy Data ECC";
+ break;
+ case FERR_NF_M6ERR:
+ specific = "Aliased Uncorrectable Mirrored Demand "
+ "Data ECC";
+ break;
+ case FERR_NF_M5ERR:
+ specific = "Aliased Uncorrectable Non-Mirrored Demand "
+ "Data ECC";
+ break;
+ case FERR_NF_M4ERR:
+ specific = "Uncorrectable Data ECC on Replay";
+ break;
+ }
+
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
- "CAS=%d, UE Err=0x%x)",
+ "CAS=%d, UE Err=0x%x (%s))",
branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
- ue_errors);
+ ue_errors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
@@ -616,51 +662,74 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
rank, channel, branch >> 1, bank,
rdwr ? "Write" : "Read", ras, cas);
+ switch (ce_errors) {
+ case FERR_NF_M17ERR:
+ specific = "Correctable Non-Mirrored Demand Data ECC";
+ break;
+ case FERR_NF_M18ERR:
+ specific = "Correctable Mirrored Demand Data ECC";
+ break;
+ case FERR_NF_M19ERR:
+ specific = "Correctable Spare-Copy Data ECC";
+ break;
+ case FERR_NF_M20ERR:
+ specific = "Correctable Patrol Data ECC";
+ break;
+ }
+
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
- "CAS=%d, CE Err=0x%x)", branch >> 1, bank,
- rdwr ? "Write" : "Read", ras, cas, ce_errors);
+ "CAS=%d, CE Err=0x%x (%s))", branch >> 1, bank,
+ rdwr ? "Write" : "Read", ras, cas, ce_errors,
+ specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ce(mci, rank, channel, msg);
}
- /* See if any of the thermal errors have fired */
- misc_errors = allErrors & FERR_NF_THERMAL;
- if (misc_errors) {
- i5000_printk(KERN_WARNING, "\tTHERMAL Error, bits= 0x%x\n",
- misc_errors);
- }
-
- /* See if any of the thermal errors have fired */
- misc_errors = allErrors & FERR_NF_NON_RETRY;
- if (misc_errors) {
- i5000_printk(KERN_WARNING, "\tNON-Retry Errors, bits= 0x%x\n",
- misc_errors);
- }
+ if (!misc_messages)
+ return;
- /* See if any of the thermal errors have fired */
- misc_errors = allErrors & FERR_NF_NORTH_CRC;
+ misc_errors = allErrors & (FERR_NF_NON_RETRY | FERR_NF_NORTH_CRC |
+ FERR_NF_SPD_PROTOCOL | FERR_NF_DIMM_SPARE);
if (misc_errors) {
- i5000_printk(KERN_WARNING,
- "\tNORTHBOUND CRC Error, bits= 0x%x\n",
- misc_errors);
- }
+ switch (misc_errors) {
+ case FERR_NF_M13ERR:
+ specific = "Non-Retry or Redundant Retry FBD Memory "
+ "Alert or Redundant Fast Reset Timeout";
+ break;
+ case FERR_NF_M14ERR:
+ specific = "Non-Retry or Redundant Retry FBD "
+ "Configuration Alert";
+ break;
+ case FERR_NF_M15ERR:
+ specific = "Non-Retry or Redundant Retry FBD "
+ "Northbound CRC error on read data";
+ break;
+ case FERR_NF_M21ERR:
+ specific = "FBD Northbound CRC error on "
+ "FBD Sync Status";
+ break;
+ case FERR_NF_M22ERR:
+ specific = "SPD protocol error";
+ break;
+ case FERR_NF_M27ERR:
+ specific = "DIMM-spare copy started";
+ break;
+ case FERR_NF_M28ERR:
+ specific = "DIMM-spare copy completed";
+ break;
+ }
+ branch = EXTRACT_FBDCHAN_INDX(info->ferr_nf_fbd);
- /* See if any of the thermal errors have fired */
- misc_errors = allErrors & FERR_NF_SPD_PROTOCOL;
- if (misc_errors) {
- i5000_printk(KERN_WARNING,
- "\tSPD Protocol Error, bits= 0x%x\n",
- misc_errors);
- }
+ /* Form out message */
+ snprintf(msg, sizeof(msg),
+ "(Branch=%d Err=%#x (%s))", branch >> 1,
+ misc_errors, specific);
- /* See if any of the thermal errors have fired */
- misc_errors = allErrors & FERR_NF_DIMM_SPARE;
- if (misc_errors) {
- i5000_printk(KERN_WARNING, "\tDIMM-Spare Error, bits= 0x%x\n",
- misc_errors);
+ /* Call the helper to output message */
+ edac_mc_handle_fbd_ce(mci, 0, 0, msg);
}
}
@@ -1497,3 +1566,6 @@ MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+module_param(misc_messages, int, 0444);
+MODULE_PARM_DESC(misc_messages, "Log miscellaneous non fatal messages");
+
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index c5305e3ee43..577760a82a0 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -114,6 +114,12 @@ struct i82443bxgx_edacmc_error_info {
static struct edac_pci_ctl_info *i82443bxgx_pci;
+static struct pci_dev *mci_pdev; /* init dev: in case that AGP code has
+ * already registered driver
+ */
+
+static int i82443bxgx_registered = 1;
+
static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
struct i82443bxgx_edacmc_error_info
*info)
@@ -345,10 +351,17 @@ EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
+ int rc;
+
debugf0("MC: " __FILE__ ": %s()\n", __func__);
/* don't need to call pci_device_enable() */
- return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+ rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+
+ if (mci_pdev == NULL)
+ mci_pdev = pci_dev_get(pdev);
+
+ return rc;
}
static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
@@ -387,15 +400,61 @@ static struct pci_driver i82443bxgx_edacmc_driver = {
static int __init i82443bxgx_edacmc_init(void)
{
+ int pci_rc;
/* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init();
- return pci_register_driver(&i82443bxgx_edacmc_driver);
+ pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
+ if (pci_rc < 0)
+ goto fail0;
+
+ if (mci_pdev == NULL) {
+ const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
+ int i = 0;
+ i82443bxgx_registered = 0;
+
+ while (mci_pdev == NULL && id->vendor != 0) {
+ mci_pdev = pci_get_device(id->vendor,
+ id->device, NULL);
+ i++;
+ id = &i82443bxgx_pci_tbl[i];
+ }
+ if (!mci_pdev) {
+ debugf0("i82443bxgx pci_get_device fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+
+ pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
+
+ if (pci_rc < 0) {
+ debugf0("i82443bxgx init fail\n");
+ pci_rc = -ENODEV;
+ goto fail1;
+ }
+ }
+
+ return 0;
+
+fail1:
+ pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+fail0:
+ if (mci_pdev != NULL)
+ pci_dev_put(mci_pdev);
+
+ return pci_rc;
}
static void __exit i82443bxgx_edacmc_exit(void)
{
pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+ if (!i82443bxgx_registered)
+ i82443bxgx_edacmc_remove_one(mci_pdev);
+
+ if (mci_pdev)
+ pci_dev_put(mci_pdev);
}
module_init(i82443bxgx_edacmc_init);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 2265d9ca153..0cfcb2d075a 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -17,6 +17,7 @@
#include <linux/io.h>
#include <linux/mod_devicetable.h>
#include <linux/edac.h>
+#include <linux/smp.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
@@ -40,7 +41,7 @@ static u32 orig_pci_err_en;
#endif
static u32 orig_l2_err_disable;
-static u32 orig_hid1;
+static u32 orig_hid1[2];
/************************ MC SYSFS parts ***********************************/
@@ -647,6 +648,9 @@ static struct of_device_id mpc85xx_l2_err_of_match[] = {
{
.compatible = "fsl,8568-l2-cache-controller",
},
+ {
+ .compatible = "fsl,mpc8572-l2-cache-controller",
+ },
{},
};
@@ -912,7 +916,8 @@ static int __devinit mpc85xx_mc_err_probe(struct of_device *op,
/* register interrupts */
pdata->irq = irq_of_parse_and_map(op->node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
- mpc85xx_mc_isr, IRQF_DISABLED,
+ mpc85xx_mc_isr,
+ IRQF_DISABLED | IRQF_SHARED,
"[EDAC] MC err", mci);
if (res < 0) {
printk(KERN_ERR "%s: Unable to request irq %d for "
@@ -980,6 +985,9 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = {
{
.compatible = "fsl,8568-memory-controller",
},
+ {
+ .compatible = "fsl,mpc8572-memory-controller",
+ },
{},
};
@@ -995,6 +1003,14 @@ static struct of_platform_driver mpc85xx_mc_err_driver = {
},
};
+
+static void __init mpc85xx_mc_clear_rfxe(void *data)
+{
+ orig_hid1[smp_processor_id()] = mfspr(SPRN_HID1);
+ mtspr(SPRN_HID1, (orig_hid1[smp_processor_id()] & ~0x20000));
+}
+
+
static int __init mpc85xx_mc_init(void)
{
int res = 0;
@@ -1030,19 +1046,22 @@ static int __init mpc85xx_mc_init(void)
* need to clear HID1[RFXE] to disable machine check int
* so we can catch it
*/
- if (edac_op_state == EDAC_OPSTATE_INT) {
- orig_hid1 = mfspr(SPRN_HID1);
- mtspr(SPRN_HID1, (orig_hid1 & ~0x20000));
- }
+ if (edac_op_state == EDAC_OPSTATE_INT)
+ on_each_cpu(mpc85xx_mc_clear_rfxe, NULL, 0);
return 0;
}
module_init(mpc85xx_mc_init);
+static void __exit mpc85xx_mc_restore_hid1(void *data)
+{
+ mtspr(SPRN_HID1, orig_hid1[smp_processor_id()]);
+}
+
static void __exit mpc85xx_mc_exit(void)
{
- mtspr(SPRN_HID1, orig_hid1);
+ on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
#ifdef CONFIG_PCI
of_unregister_platform_driver(&mpc85xx_pci_err_driver);
#endif
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 8d2940517c9..9112830107a 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -67,17 +67,28 @@ static inline void desc_set_label(struct gpio_desc *d, const char *label)
* when setting direction, and otherwise illegal. Until board setup code
* and drivers use explicit requests everywhere (which won't happen when
* those calls have no teeth) we can't avoid autorequesting. This nag
- * message should motivate switching to explicit requests...
+ * message should motivate switching to explicit requests... so should
+ * the weaker cleanup after faults, compared to gpio_request().
*/
-static void gpio_ensure_requested(struct gpio_desc *desc)
+static int gpio_ensure_requested(struct gpio_desc *desc, unsigned offset)
{
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
- pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
+ struct gpio_chip *chip = desc->chip;
+ int gpio = chip->base + offset;
+
+ if (!try_module_get(chip->owner)) {
+ pr_err("GPIO-%d: module can't be gotten \n", gpio);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
+ /* lose */
+ return -EIO;
+ }
+ pr_warning("GPIO-%d autorequested\n", gpio);
desc_set_label(desc, "[auto]");
- if (!try_module_get(desc->chip->owner))
- pr_err("GPIO-%d: module can't be gotten \n",
- (int)(desc - gpio_desc));
+ /* caller must chip->request() w/o spinlock */
+ if (chip->request)
+ return 1;
}
+ return 0;
}
/* caller holds gpio_lock *OR* gpio is marked as requested */
@@ -752,6 +763,7 @@ EXPORT_SYMBOL_GPL(gpiochip_remove);
int gpio_request(unsigned gpio, const char *label)
{
struct gpio_desc *desc;
+ struct gpio_chip *chip;
int status = -EINVAL;
unsigned long flags;
@@ -760,14 +772,15 @@ int gpio_request(unsigned gpio, const char *label)
if (!gpio_is_valid(gpio))
goto done;
desc = &gpio_desc[gpio];
- if (desc->chip == NULL)
+ chip = desc->chip;
+ if (chip == NULL)
goto done;
- if (!try_module_get(desc->chip->owner))
+ if (!try_module_get(chip->owner))
goto done;
/* NOTE: gpio_request() can be called in early boot,
- * before IRQs are enabled.
+ * before IRQs are enabled, for non-sleeping (SOC) GPIOs.
*/
if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
@@ -775,7 +788,20 @@ int gpio_request(unsigned gpio, const char *label)
status = 0;
} else {
status = -EBUSY;
- module_put(desc->chip->owner);
+ module_put(chip->owner);
+ }
+
+ if (chip->request) {
+ /* chip->request may sleep */
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ status = chip->request(chip, gpio - chip->base);
+ spin_lock_irqsave(&gpio_lock, flags);
+
+ if (status < 0) {
+ desc_set_label(desc, NULL);
+ module_put(chip->owner);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
+ }
}
done:
@@ -791,6 +817,9 @@ void gpio_free(unsigned gpio)
{
unsigned long flags;
struct gpio_desc *desc;
+ struct gpio_chip *chip;
+
+ might_sleep();
if (!gpio_is_valid(gpio)) {
WARN_ON(extra_checks);
@@ -802,9 +831,17 @@ void gpio_free(unsigned gpio)
spin_lock_irqsave(&gpio_lock, flags);
desc = &gpio_desc[gpio];
- if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags)) {
+ chip = desc->chip;
+ if (chip && test_bit(FLAG_REQUESTED, &desc->flags)) {
+ if (chip->free) {
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ might_sleep_if(extra_checks && chip->can_sleep);
+ chip->free(chip, gpio - chip->base);
+ spin_lock_irqsave(&gpio_lock, flags);
+ }
desc_set_label(desc, NULL);
module_put(desc->chip->owner);
+ clear_bit(FLAG_REQUESTED, &desc->flags);
} else
WARN_ON(extra_checks);
@@ -869,7 +906,9 @@ int gpio_direction_input(unsigned gpio)
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
- gpio_ensure_requested(desc);
+ status = gpio_ensure_requested(desc, gpio);
+ if (status < 0)
+ goto fail;
/* now we know the gpio is valid and chip won't vanish */
@@ -877,9 +916,22 @@ int gpio_direction_input(unsigned gpio)
might_sleep_if(extra_checks && chip->can_sleep);
+ if (status) {
+ status = chip->request(chip, gpio);
+ if (status < 0) {
+ pr_debug("GPIO-%d: chip request fail, %d\n",
+ chip->base + gpio, status);
+ /* and it's not available to anyone else ...
+ * gpio_request() is the fully clean solution.
+ */
+ goto lose;
+ }
+ }
+
status = chip->direction_input(chip, gpio);
if (status == 0)
clear_bit(FLAG_IS_OUT, &desc->flags);
+lose:
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -907,7 +959,9 @@ int gpio_direction_output(unsigned gpio, int value)
gpio -= chip->base;
if (gpio >= chip->ngpio)
goto fail;
- gpio_ensure_requested(desc);
+ status = gpio_ensure_requested(desc, gpio);
+ if (status < 0)
+ goto fail;
/* now we know the gpio is valid and chip won't vanish */
@@ -915,9 +969,22 @@ int gpio_direction_output(unsigned gpio, int value)
might_sleep_if(extra_checks && chip->can_sleep);
+ if (status) {
+ status = chip->request(chip, gpio);
+ if (status < 0) {
+ pr_debug("GPIO-%d: chip request fail, %d\n",
+ chip->base + gpio, status);
+ /* and it's not available to anyone else ...
+ * gpio_request() is the fully clean solution.
+ */
+ goto lose;
+ }
+ }
+
status = chip->direction_output(chip, gpio, value);
if (status == 0)
set_bit(FLAG_IS_OUT, &desc->flags);
+lose:
return status;
fail:
spin_unlock_irqrestore(&gpio_lock, flags);
@@ -1008,6 +1075,24 @@ int __gpio_cansleep(unsigned gpio)
}
EXPORT_SYMBOL_GPL(__gpio_cansleep);
+/**
+ * __gpio_to_irq() - return the IRQ corresponding to a GPIO
+ * @gpio: gpio whose IRQ will be returned (already requested)
+ * Context: any
+ *
+ * This is used directly or indirectly to implement gpio_to_irq().
+ * It returns the number of the IRQ signaled by this (input) GPIO,
+ * or a negative errno.
+ */
+int __gpio_to_irq(unsigned gpio)
+{
+ struct gpio_chip *chip;
+
+ chip = gpio_to_chip(gpio);
+ return chip->to_irq ? chip->to_irq(chip, gpio - chip->base) : -ENXIO;
+}
+EXPORT_SYMBOL_GPL(__gpio_to_irq);
+
/* There's no value in making it easy to inline GPIO calls that may sleep.
diff --git a/drivers/gpio/max7301.c b/drivers/gpio/max7301.c
index 39c795ad831..8b24d784db9 100644
--- a/drivers/gpio/max7301.c
+++ b/drivers/gpio/max7301.c
@@ -255,10 +255,6 @@ static int __devinit max7301_probe(struct spi_device *spi)
ts->chip.dev = &spi->dev;
ts->chip.owner = THIS_MODULE;
- ret = gpiochip_add(&ts->chip);
- if (ret)
- goto exit_destroy;
-
/*
* tristate all pins in hardware and cache the
* register values for later use.
@@ -269,17 +265,19 @@ static int __devinit max7301_probe(struct spi_device *spi)
max7301_write(spi, 0x08 + i, 0xAA);
ts->port_config[i] = 0xAA;
for (j = 0; j < 4; j++) {
- int idx = ts->chip.base + (i - 1) * 4 + j;
- ret = gpio_direction_input(idx);
+ int offset = (i - 1) * 4 + j;
+ ret = max7301_direction_input(&ts->chip, offset);
if (ret)
- goto exit_remove;
- gpio_free(idx);
+ goto exit_destroy;
}
}
+
+ ret = gpiochip_add(&ts->chip);
+ if (ret)
+ goto exit_destroy;
+
return ret;
-exit_remove:
- gpiochip_remove(&ts->chip);
exit_destroy:
dev_set_drvdata(&spi->dev, NULL);
mutex_destroy(&ts->lock);
@@ -325,13 +323,15 @@ static int __init max7301_init(void)
{
return spi_register_driver(&max7301_driver);
}
+/* register after spi postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(max7301_init);
static void __exit max7301_exit(void)
{
spi_unregister_driver(&max7301_driver);
}
-
-module_init(max7301_init);
module_exit(max7301_exit);
MODULE_AUTHOR("Juergen Beisert");
diff --git a/drivers/gpio/max732x.c b/drivers/gpio/max732x.c
index b51c8135ca2..55ae9a41897 100644
--- a/drivers/gpio/max732x.c
+++ b/drivers/gpio/max732x.c
@@ -372,7 +372,10 @@ static int __init max732x_init(void)
{
return i2c_add_driver(&max732x_driver);
}
-module_init(max732x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(max732x_init);
static void __exit max732x_exit(void)
{
diff --git a/drivers/gpio/mcp23s08.c b/drivers/gpio/mcp23s08.c
index 8a1b405fefd..89c1d222e9d 100644
--- a/drivers/gpio/mcp23s08.c
+++ b/drivers/gpio/mcp23s08.c
@@ -419,7 +419,10 @@ static int __init mcp23s08_init(void)
{
return spi_register_driver(&mcp23s08_driver);
}
-module_init(mcp23s08_init);
+/* register after spi postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(mcp23s08_init);
static void __exit mcp23s08_exit(void)
{
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index cc8468692ae..9ceeb89f132 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -289,7 +289,10 @@ static int __init pca953x_init(void)
{
return i2c_add_driver(&pca953x_driver);
}
-module_init(pca953x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(pca953x_init);
static void __exit pca953x_exit(void)
{
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
index fc9c6ae739e..4bc2070dd4a 100644
--- a/drivers/gpio/pcf857x.c
+++ b/drivers/gpio/pcf857x.c
@@ -351,7 +351,10 @@ static int __init pcf857x_init(void)
{
return i2c_add_driver(&pcf857x_driver);
}
-module_init(pcf857x_init);
+/* register after i2c postcore initcall and before
+ * subsys initcalls that may rely on these GPIOs
+ */
+subsys_initcall(pcf857x_init);
static void __exit pcf857x_exit(void)
{
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 88974342933..9ac4720e647 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -517,7 +517,7 @@ static int i915_dispatch_flip(struct drm_device * dev)
RING_LOCALS;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
+ __func__,
dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page);
@@ -642,7 +642,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
static int i915_flip_bufs(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
LOCK_TEST_WITH_RETURN(dev, file_priv);
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index cacf89e65af..da64108de77 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -17,6 +17,25 @@ config HID
tristate "Generic HID support"
depends on INPUT
default y
+ select HID_A4TECH if !EMBEDDED
+ select HID_APPLE if !EMBEDDED
+ select HID_BELKIN if !EMBEDDED
+ select HID_BRIGHT if !EMBEDDED
+ select HID_CHERRY if !EMBEDDED
+ select HID_CHICONY if !EMBEDDED
+ select HID_CYPRESS if !EMBEDDED
+ select HID_DELL if !EMBEDDED
+ select HID_EZKEY if !EMBEDDED
+ select HID_GYRATION if !EMBEDDED
+ select HID_LOGITECH if !EMBEDDED
+ select HID_MICROSOFT if !EMBEDDED
+ select HID_MONTEREY if !EMBEDDED
+ select HID_PANTHERLORD if !EMBEDDED
+ select HID_PETALYNX if !EMBEDDED
+ select HID_SAMSUNG if !EMBEDDED
+ select HID_SONY if !EMBEDDED
+ select HID_SUNPLUS if !EMBEDDED
+
---help---
A human interface device (HID) is a type of computer device that
interacts directly with and takes input from humans. The term "HID"
@@ -67,4 +86,206 @@ config HIDRAW
source "drivers/hid/usbhid/Kconfig"
+menu "Special HID drivers"
+ depends on HID
+
+config HID_COMPAT
+ bool "Load all HID drivers on hid core load"
+ default y
+ ---help---
+ Compatible option for older userspace. If you have system without udev
+ support of module loading through aliases and also old
+ module-init-tools which can't handle hid bus, choose Y here. Otherwise
+ say N. If you say N and your userspace is old enough, the only
+ functionality you lose is modules autoloading.
+
+ If unsure, say Y.
+
+config HID_A4TECH
+ tristate "A4 tech"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for A4 tech X5 and WOP-35 / Trust 450L mice.
+
+config HID_APPLE
+ tristate "Apple"
+ default m
+ depends on (USB_HID || BT_HIDP)
+ ---help---
+ Support for some Apple devices which less or more break
+ HID specification.
+
+ Say Y here if you want support for the special keys (Fn, Numlock) on
+ Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
+ keyboards.
+
+ If unsure, say M.
+
+config HID_BELKIN
+ tristate "Belkin"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Belkin Flip KVM and Wireless keyboard.
+
+config HID_BRIGHT
+ tristate "Bright"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Bright ABNT-2 keyboard.
+
+config HID_CHERRY
+ tristate "Cherry"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Cherry Cymotion.
+
+config HID_CHICONY
+ tristate "Chicony"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Chicony Tactical pad.
+
+config HID_CYPRESS
+ tristate "Cypress"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Cypress mouse and barcodes.
+
+config HID_DELL
+ tristate "Dell"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Dell W7658.
+
+config HID_EZKEY
+ tristate "Ezkey"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Ezkey mouse and barcodes.
+
+config HID_GYRATION
+ tristate "Gyration"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Gyration remote.
+
+config HID_LOGITECH
+ tristate "Logitech"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for some Logitech devices which breaks less or more
+ HID specification.
+
+config LOGITECH_FF
+ bool "Logitech force feedback"
+ depends on HID_LOGITECH
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you have one of these devices:
+ - Logitech WingMan Cordless RumblePad
+ - Logitech WingMan Cordless RumblePad 2
+ - Logitech WingMan Force 3D
+ - Logitech Formula Force EX
+ - Logitech MOMO Force wheel
+
+ and if you want to enable force feedback for them.
+ Note: if you say N here, this device will still be supported, but without
+ force feedback.
+
+config LOGIRUMBLEPAD2_FF
+ bool "Logitech Rumblepad 2 force feedback"
+ depends on HID_LOGITECH
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you want to enable force feedback support for Logitech
+ Rumblepad 2 devices.
+
+config HID_MICROSOFT
+ tristate "Microsoft"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for some Microsoft devices which breaks less or more
+ HID specification.
+
+config HID_MONTEREY
+ tristate "Monterey"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Monterey Genius KB29E.
+
+config HID_PANTHERLORD
+ tristate "Pantherlord devices support"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for PantherLord/GreenAsia based device support.
+
+
+config PANTHERLORD_FF
+ bool "Pantherlord force feedback support"
+ depends on HID_PANTHERLORD
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you have a PantherLord/GreenAsia based game controller
+ or adapter and want to enable force feedback support for it.
+
+config HID_PETALYNX
+ tristate "Petalynx"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Petalynx Maxter remote.
+
+config HID_SAMSUNG
+ tristate "Samsung"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Samsung IR remote.
+
+config HID_SONY
+ tristate "Sony"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Sony PS3 controller.
+
+config HID_SUNPLUS
+ tristate "Sunplus"
+ default m
+ depends on USB_HID
+ ---help---
+ Support for Sunplus WDesktop input device.
+
+config THRUSTMASTER_FF
+ tristate "ThrustMaster devices support"
+ default m
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
+ a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel.
+
+config ZEROPLUS_FF
+ tristate "Zeroplus based game controller support"
+ default m
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ help
+ Say Y here if you have a Zeroplus based game controller.
+
+endmenu
+
endif # HID_SUPPORT
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 275dc522c73..b09e43e7413 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,13 +1,46 @@
#
# Makefile for the HID driver
#
-hid-objs := hid-core.o hid-input.o hid-input-quirks.o
+hid-objs := hid-core.o hid-input.o
obj-$(CONFIG_HID) += hid.o
hid-$(CONFIG_HID_DEBUG) += hid-debug.o
hid-$(CONFIG_HIDRAW) += hidraw.o
+ifdef CONFIG_HID_COMPAT
+obj-m += hid-dummy.o
+endif
+
+hid-logitech-objs := hid-lg.o
+ifdef CONFIG_LOGITECH_FF
+ hid-logitech-objs += hid-lgff.o
+endif
+ifdef CONFIG_LOGIRUMBLEPAD2_FF
+ hid-logitech-objs += hid-lg2ff.o
+endif
+
+obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
+obj-$(CONFIG_HID_APPLE) += hid-apple.o
+obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
+obj-$(CONFIG_HID_BRIGHT) += hid-bright.o
+obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
+obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
+obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o
+obj-$(CONFIG_HID_DELL) += hid-dell.o
+obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
+obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
+obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
+obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
+obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
+obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
+obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
+obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
+obj-$(CONFIG_HID_SONY) += hid-sony.o
+obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o
+obj-$(CONFIG_THRUSTMASTER_FF) += hid-tmff.o
+obj-$(CONFIG_ZEROPLUS_FF) += hid-zpff.o
+
obj-$(CONFIG_USB_HID) += usbhid/
obj-$(CONFIG_USB_MOUSE) += usbhid/
obj-$(CONFIG_USB_KBD) += usbhid/
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
new file mode 100644
index 00000000000..ebca00e6c10
--- /dev/null
+++ b/drivers/hid/hid-a4tech.c
@@ -0,0 +1,162 @@
+/*
+ * HID driver for some a4tech "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define A4_2WHEEL_MOUSE_HACK_7 0x01
+#define A4_2WHEEL_MOUSE_HACK_B8 0x02
+
+struct a4tech_sc {
+ unsigned long quirks;
+ unsigned int hw_wheel;
+ __s32 delayed_value;
+};
+
+static int a4_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+ if (usage->type == EV_REL && usage->code == REL_WHEEL)
+ set_bit(REL_HWHEEL, *bit);
+
+ if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007)
+ return -1;
+
+ return 0;
+}
+
+static int a4_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+ struct input_dev *input;
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+ !usage->type)
+ return 0;
+
+ input = field->hidinput->input;
+
+ if (a4->quirks & A4_2WHEEL_MOUSE_HACK_B8) {
+ if (usage->type == EV_REL && usage->code == REL_WHEEL) {
+ a4->delayed_value = value;
+ return 1;
+ }
+
+ if (usage->hid == 0x000100b8) {
+ input_event(input, EV_REL, value ? REL_HWHEEL :
+ REL_WHEEL, a4->delayed_value);
+ return 1;
+ }
+ }
+
+ if ((a4->quirks & A4_2WHEEL_MOUSE_HACK_7) && usage->hid == 0x00090007) {
+ a4->hw_wheel = !!value;
+ return 1;
+ }
+
+ if (usage->code == REL_WHEEL && a4->hw_wheel) {
+ input_event(input, usage->type, REL_HWHEEL, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct a4tech_sc *a4;
+ int ret;
+
+ a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
+ if (a4 == NULL) {
+ dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ a4->quirks = id->driver_data;
+
+ hid_set_drvdata(hdev, a4);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ kfree(a4);
+ return ret;
+}
+
+static void a4_remove(struct hid_device *hdev)
+{
+ struct a4tech_sc *a4 = hid_get_drvdata(hdev);
+
+ hid_hw_stop(hdev);
+ kfree(a4);
+}
+
+static const struct hid_device_id a4_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU),
+ .driver_data = A4_2WHEEL_MOUSE_HACK_7 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D),
+ .driver_data = A4_2WHEEL_MOUSE_HACK_B8 },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, a4_devices);
+
+static struct hid_driver a4_driver = {
+ .name = "a4tech",
+ .id_table = a4_devices,
+ .input_mapped = a4_input_mapped,
+ .event = a4_event,
+ .probe = a4_probe,
+ .remove = a4_remove,
+};
+
+static int a4_init(void)
+{
+ return hid_register_driver(&a4_driver);
+}
+
+static void a4_exit(void)
+{
+ hid_unregister_driver(&a4_driver);
+}
+
+module_init(a4_init);
+module_exit(a4_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(a4tech);
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
new file mode 100644
index 00000000000..fd7f896b34f
--- /dev/null
+++ b/drivers/hid/hid-apple.c
@@ -0,0 +1,484 @@
+/*
+ * USB HID quirks support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby <jirislaby@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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+#define APPLE_RDESC_JIS 0x0001
+#define APPLE_IGNORE_MOUSE 0x0002
+#define APPLE_HAS_FN 0x0004
+#define APPLE_HIDDEV 0x0008
+#define APPLE_ISO_KEYBOARD 0x0010
+#define APPLE_MIGHTYMOUSE 0x0020
+#define APPLE_INVERT_HWHEEL 0x0040
+#define APPLE_IGNORE_HIDINPUT 0x0080
+#define APPLE_NUMLOCK_EMULATION 0x0100
+
+#define APPLE_FLAG_FKEY 0x01
+
+static unsigned int fnmode = 1;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Mode of fn key on Apple keyboards (0 = disabled, "
+ "[1] = fkeyslast, 2 = fkeysfirst)");
+
+struct apple_sc {
+ unsigned long quirks;
+ unsigned int fn_on;
+ DECLARE_BITMAP(pressed_fn, KEY_CNT);
+ DECLARE_BITMAP(pressed_numlock, KEY_CNT);
+};
+
+struct apple_key_translation {
+ u16 from;
+ u16 to;
+ u8 flags;
+};
+
+static struct apple_key_translation apple_fn_keys[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_FN_F5, APPLE_FLAG_FKEY }, /* Exposé */
+ { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */
+ { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
+ { }
+};
+
+static struct apple_key_translation powerbook_fn_keys[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
+ { }
+};
+
+static struct apple_key_translation powerbook_numlock_keys[] = {
+ { KEY_J, KEY_KP1 },
+ { KEY_K, KEY_KP2 },
+ { KEY_L, KEY_KP3 },
+ { KEY_U, KEY_KP4 },
+ { KEY_I, KEY_KP5 },
+ { KEY_O, KEY_KP6 },
+ { KEY_7, KEY_KP7 },
+ { KEY_8, KEY_KP8 },
+ { KEY_9, KEY_KP9 },
+ { KEY_M, KEY_KP0 },
+ { KEY_DOT, KEY_KPDOT },
+ { KEY_SLASH, KEY_KPPLUS },
+ { KEY_SEMICOLON, KEY_KPMINUS },
+ { KEY_P, KEY_KPASTERISK },
+ { KEY_MINUS, KEY_KPEQUAL },
+ { KEY_0, KEY_KPSLASH },
+ { KEY_F6, KEY_NUMLOCK },
+ { KEY_KPENTER, KEY_KPENTER },
+ { KEY_BACKSPACE, KEY_BACKSPACE },
+ { }
+};
+
+static struct apple_key_translation apple_iso_keyboard[] = {
+ { KEY_GRAVE, KEY_102ND },
+ { KEY_102ND, KEY_GRAVE },
+ { }
+};
+
+static struct apple_key_translation *apple_find_translation(
+ struct apple_key_translation *table, u16 from)
+{
+ struct apple_key_translation *trans;
+
+ /* Look for the translation */
+ for (trans = table; trans->from; trans++)
+ if (trans->from == from)
+ return trans;
+
+ return NULL;
+}
+
+static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
+ struct hid_usage *usage, __s32 value)
+{
+ struct apple_sc *asc = hid_get_drvdata(hid);
+ struct apple_key_translation *trans;
+
+ if (usage->code == KEY_FN) {
+ asc->fn_on = !!value;
+ input_event(input, usage->type, usage->code, value);
+ return 1;
+ }
+
+ if (fnmode) {
+ int do_translate;
+
+ trans = apple_find_translation((hid->product < 0x220 ||
+ hid->product >= 0x300) ?
+ powerbook_fn_keys : apple_fn_keys,
+ usage->code);
+ if (trans) {
+ if (test_bit(usage->code, asc->pressed_fn))
+ do_translate = 1;
+ else if (trans->flags & APPLE_FLAG_FKEY)
+ do_translate = (fnmode == 2 && asc->fn_on) ||
+ (fnmode == 1 && !asc->fn_on);
+ else
+ do_translate = asc->fn_on;
+
+ if (do_translate) {
+ if (value)
+ set_bit(usage->code, asc->pressed_fn);
+ else
+ clear_bit(usage->code, asc->pressed_fn);
+
+ input_event(input, usage->type, trans->to,
+ value);
+
+ return 1;
+ }
+ }
+
+ if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
+ (test_bit(usage->code, asc->pressed_numlock) ||
+ test_bit(LED_NUML, input->led))) {
+ trans = apple_find_translation(powerbook_numlock_keys,
+ usage->code);
+
+ if (trans) {
+ if (value)
+ set_bit(usage->code,
+ asc->pressed_numlock);
+ else
+ clear_bit(usage->code,
+ asc->pressed_numlock);
+
+ input_event(input, usage->type, trans->to,
+ value);
+ }
+
+ return 1;
+ }
+ }
+
+ if (asc->quirks & APPLE_ISO_KEYBOARD) {
+ trans = apple_find_translation(apple_iso_keyboard, usage->code);
+ if (trans) {
+ input_event(input, usage->type, trans->to, value);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int apple_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct apple_sc *asc = hid_get_drvdata(hdev);
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+ !usage->type)
+ return 0;
+
+ if ((asc->quirks & APPLE_INVERT_HWHEEL) &&
+ usage->code == REL_HWHEEL) {
+ input_event(field->hidinput->input, usage->type, usage->code,
+ -value);
+ return 1;
+ }
+
+ if ((asc->quirks & APPLE_HAS_FN) &&
+ hidinput_apple_event(hdev, field->hidinput->input,
+ usage, value))
+ return 1;
+
+
+ return 0;
+}
+
+/*
+ * MacBook JIS keyboard has wrong logical maximum
+ */
+static void apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ struct apple_sc *asc = hid_get_drvdata(hdev);
+
+ if ((asc->quirks & APPLE_RDESC_JIS) && rsize >= 60 &&
+ rdesc[53] == 0x65 && rdesc[59] == 0x65) {
+ dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
+ "descriptor\n");
+ rdesc[53] = rdesc[59] = 0xe7;
+ }
+}
+
+static void apple_setup_input(struct input_dev *input)
+{
+ struct apple_key_translation *trans;
+
+ set_bit(KEY_NUMLOCK, input->keybit);
+
+ /* Enable all needed keys */
+ for (trans = apple_fn_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+
+ for (trans = powerbook_fn_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+
+ for (trans = powerbook_numlock_keys; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+
+ for (trans = apple_iso_keyboard; trans->from; trans++)
+ set_bit(trans->to, input->keybit);
+}
+
+static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->hid == (HID_UP_CUSTOM | 0x0003)) {
+ /* The fn key on Apple USB keyboards */
+ set_bit(EV_REP, hi->input->evbit);
+ hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_FN);
+ apple_setup_input(hi->input);
+ return 1;
+ }
+
+ /* we want the hid layer to go through standard path (set and ignore) */
+ return 0;
+}
+
+static int apple_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct apple_sc *asc = hid_get_drvdata(hdev);
+
+ if (asc->quirks & APPLE_MIGHTYMOUSE) {
+ if (usage->hid == HID_GD_Z)
+ hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
+ else if (usage->code == BTN_1)
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_2);
+ else if (usage->code == BTN_2)
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_1);
+ }
+
+ return 0;
+}
+
+static int apple_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ struct apple_sc *asc;
+ unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ int ret;
+
+ /* return something else or move to hid layer? device will reside
+ allocated */
+ if (id->bus == BUS_USB && (quirks & APPLE_IGNORE_MOUSE) &&
+ to_usb_interface(hdev->dev.parent)->cur_altsetting->
+ desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE)
+ return -ENODEV;
+
+ asc = kzalloc(sizeof(*asc), GFP_KERNEL);
+ if (asc == NULL) {
+ dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+ return -ENOMEM;
+ }
+
+ asc->quirks = quirks;
+
+ hid_set_drvdata(hdev, asc);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ if (quirks & APPLE_HIDDEV)
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+ if (quirks & APPLE_IGNORE_HIDINPUT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ kfree(asc);
+ return ret;
+}
+
+static void apple_remove(struct hid_device *hdev)
+{
+ hid_hw_stop(hdev);
+ kfree(hid_get_drvdata(hdev));
+}
+
+static const struct hid_device_id apple_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
+ .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
+ .driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
+ .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS},
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
+ .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
+ .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_IGNORE_MOUSE | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
+ .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN |
+ APPLE_IGNORE_MOUSE },
+
+ /* Apple wireless Mighty Mouse */
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c),
+ .driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, apple_devices);
+
+static struct hid_driver apple_driver = {
+ .name = "apple",
+ .id_table = apple_devices,
+ .report_fixup = apple_report_fixup,
+ .probe = apple_probe,
+ .remove = apple_remove,
+ .event = apple_event,
+ .input_mapping = apple_input_mapping,
+ .input_mapped = apple_input_mapped,
+};
+
+static int apple_init(void)
+{
+ int ret;
+
+ ret = hid_register_driver(&apple_driver);
+ if (ret)
+ printk(KERN_ERR "can't register apple driver\n");
+
+ return ret;
+}
+
+static void apple_exit(void)
+{
+ hid_unregister_driver(&apple_driver);
+}
+
+module_init(apple_init);
+module_exit(apple_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(apple);
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
new file mode 100644
index 00000000000..12c8a9ba6ed
--- /dev/null
+++ b/drivers/hid/hid-belkin.c
@@ -0,0 +1,105 @@
+/*
+ * HID driver for some belkin "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define BELKIN_HIDDEV 0x01
+#define BELKIN_WKBD 0x02
+
+#define belkin_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int belkin_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER ||
+ !(quirks & BELKIN_WKBD))
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x03a: belkin_map_key_clear(KEY_SOUND); break;
+ case 0x03b: belkin_map_key_clear(KEY_CAMERA); break;
+ case 0x03c: belkin_map_key_clear(KEY_DOCUMENTS); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ int ret;
+
+ hid_set_drvdata(hdev, (void *)quirks);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+ ((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id belkin_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM),
+ .driver_data = BELKIN_HIDDEV },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD),
+ .driver_data = BELKIN_WKBD },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, belkin_devices);
+
+static struct hid_driver belkin_driver = {
+ .name = "belkin",
+ .id_table = belkin_devices,
+ .input_mapping = belkin_input_mapping,
+ .probe = belkin_probe,
+};
+
+static int belkin_init(void)
+{
+ return hid_register_driver(&belkin_driver);
+}
+
+static void belkin_exit(void)
+{
+ hid_unregister_driver(&belkin_driver);
+}
+
+module_init(belkin_init);
+module_exit(belkin_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(belkin);
diff --git a/drivers/hid/hid-bright.c b/drivers/hid/hid-bright.c
new file mode 100644
index 00000000000..38517a117df
--- /dev/null
+++ b/drivers/hid/hid-bright.c
@@ -0,0 +1,71 @@
+/*
+ * HID driver for some bright "special" devices
+ *
+ * Copyright (c) 2008 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Based on hid-dell driver
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int bright_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ usbhid_set_leds(hdev);
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id bright_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, bright_devices);
+
+static struct hid_driver bright_driver = {
+ .name = "bright",
+ .id_table = bright_devices,
+ .probe = bright_probe,
+};
+
+static int bright_init(void)
+{
+ return hid_register_driver(&bright_driver);
+}
+
+static void bright_exit(void)
+{
+ hid_unregister_driver(&bright_driver);
+}
+
+module_init(bright_init);
+module_exit(bright_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(bright);
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
new file mode 100644
index 00000000000..b833b9769ab
--- /dev/null
+++ b/drivers/hid/hid-cherry.c
@@ -0,0 +1,87 @@
+/*
+ * HID driver for some cherry "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Cherry Cymotion keyboard have an invalid HID report descriptor,
+ * that needs fixing before we can parse it.
+ */
+static void ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
+ dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
+ "descriptor\n");
+ rdesc[11] = rdesc[16] = 0xff;
+ rdesc[12] = rdesc[17] = 0x03;
+ }
+}
+
+#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x301: ch_map_key_clear(KEY_PROG1); break;
+ case 0x302: ch_map_key_clear(KEY_PROG2); break;
+ case 0x303: ch_map_key_clear(KEY_PROG3); break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+ .name = "cherry",
+ .id_table = ch_devices,
+ .report_fixup = ch_report_fixup,
+ .input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+ return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+ hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cherry);
diff --git a/drivers/hid/hid-chicony.c b/drivers/hid/hid-chicony.c
new file mode 100644
index 00000000000..a54d4096e0f
--- /dev/null
+++ b/drivers/hid/hid-chicony.c
@@ -0,0 +1,80 @@
+/*
+ * HID driver for some chicony "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ch_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+ return 0;
+
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ case 0xff01: ch_map_key_clear(BTN_1); break;
+ case 0xff02: ch_map_key_clear(BTN_2); break;
+ case 0xff03: ch_map_key_clear(BTN_3); break;
+ case 0xff04: ch_map_key_clear(BTN_4); break;
+ case 0xff05: ch_map_key_clear(BTN_5); break;
+ case 0xff06: ch_map_key_clear(BTN_6); break;
+ case 0xff07: ch_map_key_clear(BTN_7); break;
+ case 0xff08: ch_map_key_clear(BTN_8); break;
+ case 0xff09: ch_map_key_clear(BTN_9); break;
+ case 0xff0a: ch_map_key_clear(BTN_A); break;
+ case 0xff0b: ch_map_key_clear(BTN_B); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static const struct hid_device_id ch_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ch_devices);
+
+static struct hid_driver ch_driver = {
+ .name = "chicony",
+ .id_table = ch_devices,
+ .input_mapping = ch_input_mapping,
+};
+
+static int ch_init(void)
+{
+ return hid_register_driver(&ch_driver);
+}
+
+static void ch_exit(void)
+{
+ hid_unregister_driver(&ch_driver);
+}
+
+module_init(ch_init);
+module_exit(ch_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(chicony);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 426ac5add58..8a7d9dbb4d0 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -33,6 +33,8 @@
#include <linux/hid-debug.h>
#include <linux/hidraw.h>
+#include "hid-ids.h"
+
/*
* Version Information
*/
@@ -268,9 +270,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
static u32 item_udata(struct hid_item *item)
{
switch (item->size) {
- case 1: return item->data.u8;
- case 2: return item->data.u16;
- case 4: return item->data.u32;
+ case 1: return item->data.u8;
+ case 2: return item->data.u16;
+ case 4: return item->data.u32;
}
return 0;
}
@@ -278,9 +280,9 @@ static u32 item_udata(struct hid_item *item)
static s32 item_sdata(struct hid_item *item)
{
switch (item->size) {
- case 1: return item->data.s8;
- case 2: return item->data.s16;
- case 4: return item->data.s32;
+ case 1: return item->data.s8;
+ case 2: return item->data.s16;
+ case 4: return item->data.s32;
}
return 0;
}
@@ -292,87 +294,91 @@ static s32 item_sdata(struct hid_item *item)
static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
{
switch (item->tag) {
+ case HID_GLOBAL_ITEM_TAG_PUSH:
- case HID_GLOBAL_ITEM_TAG_PUSH:
-
- if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
- dbg_hid("global enviroment stack overflow\n");
- return -1;
- }
+ if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+ dbg_hid("global enviroment stack overflow\n");
+ return -1;
+ }
- memcpy(parser->global_stack + parser->global_stack_ptr++,
- &parser->global, sizeof(struct hid_global));
- return 0;
+ memcpy(parser->global_stack + parser->global_stack_ptr++,
+ &parser->global, sizeof(struct hid_global));
+ return 0;
- case HID_GLOBAL_ITEM_TAG_POP:
+ case HID_GLOBAL_ITEM_TAG_POP:
- if (!parser->global_stack_ptr) {
- dbg_hid("global enviroment stack underflow\n");
- return -1;
- }
-
- memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
- sizeof(struct hid_global));
- return 0;
+ if (!parser->global_stack_ptr) {
+ dbg_hid("global enviroment stack underflow\n");
+ return -1;
+ }
- case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
- parser->global.usage_page = item_udata(item);
- return 0;
+ memcpy(&parser->global, parser->global_stack +
+ --parser->global_stack_ptr, sizeof(struct hid_global));
+ return 0;
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
- parser->global.logical_minimum = item_sdata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+ parser->global.usage_page = item_udata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
- if (parser->global.logical_minimum < 0)
- parser->global.logical_maximum = item_sdata(item);
- else
- parser->global.logical_maximum = item_udata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+ parser->global.logical_minimum = item_sdata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
- parser->global.physical_minimum = item_sdata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+ if (parser->global.logical_minimum < 0)
+ parser->global.logical_maximum = item_sdata(item);
+ else
+ parser->global.logical_maximum = item_udata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
- if (parser->global.physical_minimum < 0)
- parser->global.physical_maximum = item_sdata(item);
- else
- parser->global.physical_maximum = item_udata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+ parser->global.physical_minimum = item_sdata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
- parser->global.unit_exponent = item_sdata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+ if (parser->global.physical_minimum < 0)
+ parser->global.physical_maximum = item_sdata(item);
+ else
+ parser->global.physical_maximum = item_udata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_UNIT:
- parser->global.unit = item_udata(item);
- return 0;
+ case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+ parser->global.unit_exponent = item_sdata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
- if ((parser->global.report_size = item_udata(item)) > 32) {
- dbg_hid("invalid report_size %d\n", parser->global.report_size);
- return -1;
- }
- return 0;
+ case HID_GLOBAL_ITEM_TAG_UNIT:
+ parser->global.unit = item_udata(item);
+ return 0;
- case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
- if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
- dbg_hid("invalid report_count %d\n", parser->global.report_count);
- return -1;
- }
- return 0;
+ case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+ parser->global.report_size = item_udata(item);
+ if (parser->global.report_size > 32) {
+ dbg_hid("invalid report_size %d\n",
+ parser->global.report_size);
+ return -1;
+ }
+ return 0;
- case HID_GLOBAL_ITEM_TAG_REPORT_ID:
- if ((parser->global.report_id = item_udata(item)) == 0) {
- dbg_hid("report_id 0 is invalid\n");
- return -1;
- }
- return 0;
+ case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+ parser->global.report_count = item_udata(item);
+ if (parser->global.report_count > HID_MAX_USAGES) {
+ dbg_hid("invalid report_count %d\n",
+ parser->global.report_count);
+ return -1;
+ }
+ return 0;
- default:
- dbg_hid("unknown global tag 0x%x\n", item->tag);
+ case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+ parser->global.report_id = item_udata(item);
+ if (parser->global.report_id == 0) {
+ dbg_hid("report_id 0 is invalid\n");
return -1;
+ }
+ return 0;
+
+ default:
+ dbg_hid("unknown global tag 0x%x\n", item->tag);
+ return -1;
}
}
@@ -393,77 +399,76 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
data = item_udata(item);
switch (item->tag) {
-
- case HID_LOCAL_ITEM_TAG_DELIMITER:
-
- if (data) {
- /*
- * We treat items before the first delimiter
- * as global to all usage sets (branch 0).
- * In the moment we process only these global
- * items and the first delimiter set.
- */
- if (parser->local.delimiter_depth != 0) {
- dbg_hid("nested delimiters\n");
- return -1;
- }
- parser->local.delimiter_depth++;
- parser->local.delimiter_branch++;
- } else {
- if (parser->local.delimiter_depth < 1) {
- dbg_hid("bogus close delimiter\n");
- return -1;
- }
- parser->local.delimiter_depth--;
+ case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+ if (data) {
+ /*
+ * We treat items before the first delimiter
+ * as global to all usage sets (branch 0).
+ * In the moment we process only these global
+ * items and the first delimiter set.
+ */
+ if (parser->local.delimiter_depth != 0) {
+ dbg_hid("nested delimiters\n");
+ return -1;
}
- return 1;
-
- case HID_LOCAL_ITEM_TAG_USAGE:
-
- if (parser->local.delimiter_branch > 1) {
- dbg_hid("alternative usage ignored\n");
- return 0;
+ parser->local.delimiter_depth++;
+ parser->local.delimiter_branch++;
+ } else {
+ if (parser->local.delimiter_depth < 1) {
+ dbg_hid("bogus close delimiter\n");
+ return -1;
}
+ parser->local.delimiter_depth--;
+ }
+ return 1;
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
+ case HID_LOCAL_ITEM_TAG_USAGE:
- return hid_add_usage(parser, data);
+ if (parser->local.delimiter_branch > 1) {
+ dbg_hid("alternative usage ignored\n");
+ return 0;
+ }
- case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
- if (parser->local.delimiter_branch > 1) {
- dbg_hid("alternative usage ignored\n");
- return 0;
- }
+ return hid_add_usage(parser, data);
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
+ case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
- parser->local.usage_minimum = data;
+ if (parser->local.delimiter_branch > 1) {
+ dbg_hid("alternative usage ignored\n");
return 0;
+ }
- case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
- if (parser->local.delimiter_branch > 1) {
- dbg_hid("alternative usage ignored\n");
- return 0;
- }
+ parser->local.usage_minimum = data;
+ return 0;
- if (item->size <= 2)
- data = (parser->global.usage_page << 16) + data;
+ case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
- for (n = parser->local.usage_minimum; n <= data; n++)
- if (hid_add_usage(parser, n)) {
- dbg_hid("hid_add_usage failed\n");
- return -1;
- }
+ if (parser->local.delimiter_branch > 1) {
+ dbg_hid("alternative usage ignored\n");
return 0;
+ }
- default:
+ if (item->size <= 2)
+ data = (parser->global.usage_page << 16) + data;
- dbg_hid("unknown local item tag 0x%x\n", item->tag);
- return 0;
+ for (n = parser->local.usage_minimum; n <= data; n++)
+ if (hid_add_usage(parser, n)) {
+ dbg_hid("hid_add_usage failed\n");
+ return -1;
+ }
+ return 0;
+
+ default:
+
+ dbg_hid("unknown local item tag 0x%x\n", item->tag);
+ return 0;
}
return 0;
}
@@ -480,24 +485,24 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
data = item_udata(item);
switch (item->tag) {
- case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
- ret = open_collection(parser, data & 0xff);
- break;
- case HID_MAIN_ITEM_TAG_END_COLLECTION:
- ret = close_collection(parser);
- break;
- case HID_MAIN_ITEM_TAG_INPUT:
- ret = hid_add_field(parser, HID_INPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_OUTPUT:
- ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
- break;
- case HID_MAIN_ITEM_TAG_FEATURE:
- ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
- break;
- default:
- dbg_hid("unknown main item tag 0x%x\n", item->tag);
- ret = 0;
+ case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+ ret = open_collection(parser, data & 0xff);
+ break;
+ case HID_MAIN_ITEM_TAG_END_COLLECTION:
+ ret = close_collection(parser);
+ break;
+ case HID_MAIN_ITEM_TAG_INPUT:
+ ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_OUTPUT:
+ ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+ break;
+ case HID_MAIN_ITEM_TAG_FEATURE:
+ ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+ break;
+ default:
+ dbg_hid("unknown main item tag 0x%x\n", item->tag);
+ ret = 0;
}
memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */
@@ -534,9 +539,10 @@ static void hid_free_report(struct hid_report *report)
* Free a device structure, all reports, and all fields.
*/
-void hid_free_device(struct hid_device *device)
+static void hid_device_release(struct device *dev)
{
- unsigned i,j;
+ struct hid_device *device = container_of(dev, struct hid_device, dev);
+ unsigned i, j;
for (i = 0; i < HID_REPORT_TYPES; i++) {
struct hid_report_enum *report_enum = device->report_enum + i;
@@ -552,7 +558,6 @@ void hid_free_device(struct hid_device *device)
kfree(device->collection);
kfree(device);
}
-EXPORT_SYMBOL_GPL(hid_free_device);
/*
* Fetch a report description item from the data stream. We support long
@@ -593,47 +598,52 @@ static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
item->size = b & 3;
switch (item->size) {
+ case 0:
+ return start;
- case 0:
- return start;
-
- case 1:
- if ((end - start) < 1)
- return NULL;
- item->data.u8 = *start++;
- return start;
+ case 1:
+ if ((end - start) < 1)
+ return NULL;
+ item->data.u8 = *start++;
+ return start;
- case 2:
- if ((end - start) < 2)
- return NULL;
- item->data.u16 = get_unaligned_le16(start);
- start = (__u8 *)((__le16 *)start + 1);
- return start;
+ case 2:
+ if ((end - start) < 2)
+ return NULL;
+ item->data.u16 = get_unaligned_le16(start);
+ start = (__u8 *)((__le16 *)start + 1);
+ return start;
- case 3:
- item->size++;
- if ((end - start) < 4)
- return NULL;
- item->data.u32 = get_unaligned_le32(start);
- start = (__u8 *)((__le32 *)start + 1);
- return start;
+ case 3:
+ item->size++;
+ if ((end - start) < 4)
+ return NULL;
+ item->data.u32 = get_unaligned_le32(start);
+ start = (__u8 *)((__le32 *)start + 1);
+ return start;
}
return NULL;
}
-/*
+/**
+ * hid_parse_report - parse device report
+ *
+ * @device: hid device
+ * @start: report start
+ * @size: report size
+ *
* Parse a report description into a hid_device structure. Reports are
* enumerated, fields are attached to these reports.
+ * 0 returned on success, otherwise nonzero error value.
*/
-
-struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+int hid_parse_report(struct hid_device *device, __u8 *start,
+ unsigned size)
{
- struct hid_device *device;
struct hid_parser *parser;
struct hid_item item;
__u8 *end;
- unsigned i;
+ int ret;
static int (*dispatch_type[])(struct hid_parser *parser,
struct hid_item *item) = {
hid_parser_main,
@@ -642,76 +652,57 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size)
hid_parser_reserved
};
- if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL)))
- return NULL;
+ if (device->driver->report_fixup)
+ device->driver->report_fixup(device, start, size);
- if (!(device->collection = kzalloc(sizeof(struct hid_collection) *
- HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) {
- kfree(device);
- return NULL;
- }
- device->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
-
- for (i = 0; i < HID_REPORT_TYPES; i++)
- INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
- if (!(device->rdesc = kmalloc(size, GFP_KERNEL))) {
- kfree(device->collection);
- kfree(device);
- return NULL;
- }
+ device->rdesc = kmalloc(size, GFP_KERNEL);
+ if (device->rdesc == NULL)
+ return -ENOMEM;
memcpy(device->rdesc, start, size);
device->rsize = size;
- if (!(parser = vmalloc(sizeof(struct hid_parser)))) {
- kfree(device->rdesc);
- kfree(device->collection);
- kfree(device);
- return NULL;
+ parser = vmalloc(sizeof(struct hid_parser));
+ if (!parser) {
+ ret = -ENOMEM;
+ goto err;
}
+
memset(parser, 0, sizeof(struct hid_parser));
parser->device = device;
end = start + size;
+ ret = -EINVAL;
while ((start = fetch_item(start, end, &item)) != NULL) {
if (item.format != HID_ITEM_FORMAT_SHORT) {
dbg_hid("unexpected long global item\n");
- hid_free_device(device);
- vfree(parser);
- return NULL;
+ goto err;
}
if (dispatch_type[item.type](parser, &item)) {
dbg_hid("item %u %u %u %u parsing failed\n",
item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
- hid_free_device(device);
- vfree(parser);
- return NULL;
+ goto err;
}
if (start == end) {
if (parser->collection_stack_ptr) {
dbg_hid("unbalanced collection at end of report description\n");
- hid_free_device(device);
- vfree(parser);
- return NULL;
+ goto err;
}
if (parser->local.delimiter_depth) {
dbg_hid("unbalanced delimiter at end of report description\n");
- hid_free_device(device);
- vfree(parser);
- return NULL;
+ goto err;
}
vfree(parser);
- return device;
+ return 0;
}
}
dbg_hid("item fetching failed at offset %d\n", (int)(end - start));
- hid_free_device(device);
+err:
vfree(parser);
- return NULL;
+ return ret;
}
EXPORT_SYMBOL_GPL(hid_parse_report);
@@ -724,9 +715,9 @@ EXPORT_SYMBOL_GPL(hid_parse_report);
static s32 snto32(__u32 value, unsigned n)
{
switch (n) {
- case 8: return ((__s8)value);
- case 16: return ((__s16)value);
- case 32: return ((__s32)value);
+ case 8: return ((__s8)value);
+ case 16: return ((__s16)value);
+ case 32: return ((__s32)value);
}
return value & (1 << (n - 1)) ? value | (-1 << n) : value;
}
@@ -815,9 +806,73 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n)
return -1;
}
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
+/**
+ * hid_match_report - check if driver's raw_event should be called
+ *
+ * @hid: hid device
+ * @report_type: type to match against
+ *
+ * compare hid->driver->report_table->report_type to report->type
+ */
+static int hid_match_report(struct hid_device *hid, struct hid_report *report)
+{
+ const struct hid_report_id *id = hid->driver->report_table;
+
+ if (!id) /* NULL means all */
+ return 1;
+
+ for (; id->report_type != HID_TERMINATOR; id++)
+ if (id->report_type == HID_ANY_ID ||
+ id->report_type == report->type)
+ return 1;
+ return 0;
+}
+
+/**
+ * hid_match_usage - check if driver's event should be called
+ *
+ * @hid: hid device
+ * @usage: usage to match against
+ *
+ * compare hid->driver->usage_table->usage_{type,code} to
+ * usage->usage_{type,code}
+ */
+static int hid_match_usage(struct hid_device *hid, struct hid_usage *usage)
{
+ const struct hid_usage_id *id = hid->driver->usage_table;
+
+ if (!id) /* NULL means all */
+ return 1;
+
+ for (; id->usage_type != HID_ANY_ID - 1; id++)
+ if ((id->usage_hid == HID_ANY_ID ||
+ id->usage_hid == usage->hid) &&
+ (id->usage_type == HID_ANY_ID ||
+ id->usage_type == usage->type) &&
+ (id->usage_code == HID_ANY_ID ||
+ id->usage_code == usage->code))
+ return 1;
+ return 0;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value, int interrupt)
+{
+ struct hid_driver *hdrv = hid->driver;
+ int ret;
+
hid_dump_input(usage, value);
+
+ if (hdrv && hdrv->event && hid_match_usage(hid, usage)) {
+ ret = hdrv->event(hid, field, usage, value);
+ if (ret != 0) {
+ if (ret < 0)
+ dbg_hid("%s's event failed with %d\n",
+ hdrv->name, ret);
+ return;
+ }
+ }
+
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_hid_event(hid, field, usage, value);
if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event)
@@ -946,44 +1001,47 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
}
EXPORT_SYMBOL_GPL(hid_set_field);
-int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
+ const u8 *data)
{
- struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report;
- int n, rsize, i;
+ unsigned int n = 0; /* Normally report number is 0 */
- if (!hid)
- return -ENODEV;
+ /* Device uses numbered reports, data[0] is report number */
+ if (report_enum->numbered)
+ n = *data;
- if (!size) {
- dbg_hid("empty report\n");
- return -1;
- }
+ report = report_enum->report_id_hash[n];
+ if (report == NULL)
+ dbg_hid("undefined report_id %u received\n", n);
- dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+ return report;
+}
- n = 0; /* Normally report number is 0 */
- if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */
- n = *data++;
- size--;
- }
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+ int interrupt)
+{
+ struct hid_report_enum *report_enum = hid->report_enum + type;
+ struct hid_report *report;
+ unsigned int a;
+ int rsize, csize = size;
+ u8 *cdata = data;
- /* dump the report */
- dbg_hid("report %d (size %u) = ", n, size);
- for (i = 0; i < size; i++)
- dbg_hid_line(" %02x", data[i]);
- dbg_hid_line("\n");
+ report = hid_get_report(report_enum, data);
+ if (!report)
+ return;
- if (!(report = report_enum->report_id_hash[n])) {
- dbg_hid("undefined report_id %d received\n", n);
- return -1;
+ if (report_enum->numbered) {
+ cdata++;
+ csize--;
}
rsize = ((report->size - 1) >> 3) + 1;
- if (size < rsize) {
- dbg_hid("report %d is too short, (%d < %d)\n", report->id, size, rsize);
- memset(data + size, 0, rsize - size);
+ if (csize < rsize) {
+ dbg_hid("report %d is too short, (%d < %d)\n", report->id,
+ csize, rsize);
+ memset(cdata + csize, 0, rsize - csize);
}
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event)
@@ -996,24 +1054,661 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
hidraw_report_event(hid, data, size);
}
- for (n = 0; n < report->maxfield; n++)
- hid_input_field(hid, report->field[n], data, interrupt);
+ for (a = 0; a < report->maxfield; a++)
+ hid_input_field(hid, report->field[a], cdata, interrupt);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
+}
+EXPORT_SYMBOL_GPL(hid_report_raw_event);
+
+/**
+ * hid_input_report - report data from lower layer (usb, bt...)
+ *
+ * @hid: hid device
+ * @type: HID report type (HID_*_REPORT)
+ * @data: report contents
+ * @size: size of data parameter
+ * @interrupt: called from atomic?
+ *
+ * This is data entry for lower layers.
+ */
+int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt)
+{
+ struct hid_report_enum *report_enum = hid->report_enum + type;
+ struct hid_driver *hdrv = hid->driver;
+ struct hid_report *report;
+ unsigned int i;
+ int ret;
+
+ if (!hid || !hid->driver)
+ return -ENODEV;
+
+ if (!size) {
+ dbg_hid("empty report\n");
+ return -1;
+ }
+
+ dbg_hid("report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
+
+ report = hid_get_report(report_enum, data);
+ if (!report)
+ return -1;
+
+ /* dump the report */
+ dbg_hid("report %d (size %u) = ", report->id, size);
+ for (i = 0; i < size; i++)
+ dbg_hid_line(" %02x", data[i]);
+ dbg_hid_line("\n");
+
+ if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) {
+ ret = hdrv->raw_event(hid, report, data, size);
+ if (ret != 0)
+ return ret < 0 ? ret : 0;
+ }
+
+ hid_report_raw_event(hid, type, data, size, interrupt);
return 0;
}
EXPORT_SYMBOL_GPL(hid_input_report);
+static bool hid_match_one_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ return id->bus == hdev->bus &&
+ (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) &&
+ (id->product == HID_ANY_ID || id->product == hdev->product);
+}
+
+static const struct hid_device_id *hid_match_id(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ for (; id->bus; id++)
+ if (hid_match_one_id(hdev, id))
+ return id;
+
+ return NULL;
+}
+
+static const struct hid_device_id hid_hiddev_list[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) },
+ { }
+};
+
+static bool hid_hiddev(struct hid_device *hdev)
+{
+ return !!hid_match_id(hdev, hid_hiddev_list);
+}
+
+int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
+{
+ static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
+ "Joystick", "Gamepad", "Keyboard", "Keypad",
+ "Multi-Axis Controller"
+ };
+ const char *type, *bus;
+ char buf[64];
+ unsigned int i;
+ int len;
+
+ if (hdev->bus != BUS_USB)
+ connect_mask &= ~HID_CONNECT_HIDDEV;
+ if (hid_hiddev(hdev))
+ connect_mask |= HID_CONNECT_HIDDEV_FORCE;
+
+ if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev,
+ connect_mask & HID_CONNECT_HIDINPUT_FORCE))
+ hdev->claimed |= HID_CLAIMED_INPUT;
+ if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect &&
+ !hdev->hiddev_connect(hdev,
+ connect_mask & HID_CONNECT_HIDDEV_FORCE))
+ hdev->claimed |= HID_CLAIMED_HIDDEV;
+ if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
+ hdev->claimed |= HID_CLAIMED_HIDRAW;
+
+ if (!hdev->claimed) {
+ dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
+ "hidraw\n");
+ return -ENODEV;
+ }
+
+ if ((hdev->claimed & HID_CLAIMED_INPUT) &&
+ (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
+ hdev->ff_init(hdev);
+
+ len = 0;
+ if (hdev->claimed & HID_CLAIMED_INPUT)
+ len += sprintf(buf + len, "input");
+ if (hdev->claimed & HID_CLAIMED_HIDDEV)
+ len += sprintf(buf + len, "%shiddev%d", len ? "," : "",
+ hdev->minor);
+ if (hdev->claimed & HID_CLAIMED_HIDRAW)
+ len += sprintf(buf + len, "%shidraw%d", len ? "," : "",
+ ((struct hidraw *)hdev->hidraw)->minor);
+
+ type = "Device";
+ for (i = 0; i < hdev->maxcollection; i++) {
+ struct hid_collection *col = &hdev->collection[i];
+ if (col->type == HID_COLLECTION_APPLICATION &&
+ (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+ (col->usage & 0xffff) < ARRAY_SIZE(types)) {
+ type = types[col->usage & 0xffff];
+ break;
+ }
+ }
+
+ switch (hdev->bus) {
+ case BUS_USB:
+ bus = "USB";
+ break;
+ case BUS_BLUETOOTH:
+ bus = "BLUETOOTH";
+ break;
+ default:
+ bus = "<UNKNOWN>";
+ }
+
+ dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+ buf, bus, hdev->version >> 8, hdev->version & 0xff,
+ type, hdev->name, hdev->phys);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(hid_connect);
+
+static const struct hid_device_id hid_blacklist[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BRIGHT, USB_DEVICE_ID_BRIGHT_ABNT2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
+ { }
+};
+
+static int hid_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct hid_driver *hdrv = container_of(drv, struct hid_driver, driver);
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+ if (!hid_match_id(hdev, hdrv->id_table))
+ return 0;
+
+ /* generic wants all non-blacklisted */
+ if (!strncmp(hdrv->name, "generic-", 8))
+ return !hid_match_id(hdev, hid_blacklist);
+
+ return 1;
+}
+
+static int hid_device_probe(struct device *dev)
+{
+ struct hid_driver *hdrv = container_of(dev->driver,
+ struct hid_driver, driver);
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ const struct hid_device_id *id;
+ int ret = 0;
+
+ if (!hdev->driver) {
+ id = hid_match_id(hdev, hdrv->id_table);
+ if (id == NULL)
+ return -ENODEV;
+
+ hdev->driver = hdrv;
+ if (hdrv->probe) {
+ ret = hdrv->probe(hdev, id);
+ } else { /* default probe */
+ ret = hid_parse(hdev);
+ if (!ret)
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ }
+ if (ret)
+ hdev->driver = NULL;
+ }
+ return ret;
+}
+
+static int hid_device_remove(struct device *dev)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_driver *hdrv = hdev->driver;
+
+ if (hdrv) {
+ if (hdrv->remove)
+ hdrv->remove(hdev);
+ else /* default remove */
+ hid_hw_stop(hdev);
+ hdev->driver = NULL;
+ }
+
+ return 0;
+}
+
+static int hid_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+ if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X",
+ hdev->bus, hdev->vendor, hdev->product))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "HID_NAME=%s", hdev->name))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "HID_PHYS=%s", hdev->phys))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq))
+ return -ENOMEM;
+
+ if (add_uevent_var(env, "MODALIAS=hid:b%04Xv%08Xp%08X",
+ hdev->bus, hdev->vendor, hdev->product))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct bus_type hid_bus_type = {
+ .name = "hid",
+ .match = hid_bus_match,
+ .probe = hid_device_probe,
+ .remove = hid_device_remove,
+ .uevent = hid_uevent,
+};
+
+static const struct hid_device_id hid_ignore_list[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WACOM, HID_ANY_ID) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+ { }
+};
+
+static bool hid_ignore(struct hid_device *hdev)
+{
+ switch (hdev->vendor) {
+ case USB_VENDOR_ID_CODEMERCS:
+ /* ignore all Code Mercenaries IOWarrior devices */
+ if (hdev->product >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
+ hdev->product <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
+ return true;
+ break;
+ case USB_VENDOR_ID_LOGITECH:
+ if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST &&
+ hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST)
+ return true;
+ break;
+ }
+
+ return !!hid_match_id(hdev, hid_ignore_list);
+}
+
+int hid_add_device(struct hid_device *hdev)
+{
+ static atomic_t id = ATOMIC_INIT(0);
+ int ret;
+
+ if (WARN_ON(hdev->status & HID_STAT_ADDED))
+ return -EBUSY;
+
+ /* we need to kill them here, otherwise they will stay allocated to
+ * wait for coming driver */
+ if (hid_ignore(hdev))
+ return -ENODEV;
+
+ /* XXX hack, any other cleaner solution < 20 bus_id bytes? */
+ sprintf(hdev->dev.bus_id, "%04X:%04X:%04X.%04X", hdev->bus,
+ hdev->vendor, hdev->product, atomic_inc_return(&id));
+
+ ret = device_add(&hdev->dev);
+ if (!ret)
+ hdev->status |= HID_STAT_ADDED;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(hid_add_device);
+
+/**
+ * hid_allocate_device - allocate new hid device descriptor
+ *
+ * Allocate and initialize hid device, so that hid_destroy_device might be
+ * used to free it.
+ *
+ * New hid_device pointer is returned on success, otherwise ERR_PTR encoded
+ * error value.
+ */
+struct hid_device *hid_allocate_device(void)
+{
+ struct hid_device *hdev;
+ unsigned int i;
+ int ret = -ENOMEM;
+
+ hdev = kzalloc(sizeof(*hdev), GFP_KERNEL);
+ if (hdev == NULL)
+ return ERR_PTR(ret);
+
+ device_initialize(&hdev->dev);
+ hdev->dev.release = hid_device_release;
+ hdev->dev.bus = &hid_bus_type;
+
+ hdev->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS,
+ sizeof(struct hid_collection), GFP_KERNEL);
+ if (hdev->collection == NULL)
+ goto err;
+ hdev->collection_size = HID_DEFAULT_NUM_COLLECTIONS;
+
+ for (i = 0; i < HID_REPORT_TYPES; i++)
+ INIT_LIST_HEAD(&hdev->report_enum[i].report_list);
+
+ return hdev;
+err:
+ put_device(&hdev->dev);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(hid_allocate_device);
+
+static void hid_remove_device(struct hid_device *hdev)
+{
+ if (hdev->status & HID_STAT_ADDED) {
+ device_del(&hdev->dev);
+ hdev->status &= ~HID_STAT_ADDED;
+ }
+}
+
+/**
+ * hid_destroy_device - free previously allocated device
+ *
+ * @hdev: hid device
+ *
+ * If you allocate hid_device through hid_allocate_device, you should ever
+ * free by this function.
+ */
+void hid_destroy_device(struct hid_device *hdev)
+{
+ hid_remove_device(hdev);
+ put_device(&hdev->dev);
+}
+EXPORT_SYMBOL_GPL(hid_destroy_device);
+
+int __hid_register_driver(struct hid_driver *hdrv, struct module *owner,
+ const char *mod_name)
+{
+ hdrv->driver.name = hdrv->name;
+ hdrv->driver.bus = &hid_bus_type;
+ hdrv->driver.owner = owner;
+ hdrv->driver.mod_name = mod_name;
+
+ return driver_register(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(__hid_register_driver);
+
+void hid_unregister_driver(struct hid_driver *hdrv)
+{
+ driver_unregister(&hdrv->driver);
+}
+EXPORT_SYMBOL_GPL(hid_unregister_driver);
+
+#ifdef CONFIG_HID_COMPAT
+static void hid_compat_load(struct work_struct *ws)
+{
+ request_module("hid-dummy");
+}
+static DECLARE_WORK(hid_compat_work, hid_compat_load);
+static struct workqueue_struct *hid_compat_wq;
+#endif
+
static int __init hid_init(void)
{
- return hidraw_init();
+ int ret;
+
+ ret = bus_register(&hid_bus_type);
+ if (ret) {
+ printk(KERN_ERR "HID: can't register hid bus\n");
+ goto err;
+ }
+
+ ret = hidraw_init();
+ if (ret)
+ goto err_bus;
+
+#ifdef CONFIG_HID_COMPAT
+ hid_compat_wq = create_workqueue("hid_compat");
+ if (!hid_compat_wq) {
+ hidraw_exit();
+ goto err;
+ }
+ queue_work(hid_compat_wq, &hid_compat_work);
+#endif
+
+ return 0;
+err_bus:
+ bus_unregister(&hid_bus_type);
+err:
+ return ret;
}
static void __exit hid_exit(void)
{
+#ifdef CONFIG_HID_COMPAT
+ destroy_workqueue(hid_compat_wq);
+#endif
hidraw_exit();
+ bus_unregister(&hid_bus_type);
}
module_init(hid_init);
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
new file mode 100644
index 00000000000..5d69d27b935
--- /dev/null
+++ b/drivers/hid/hid-cypress.c
@@ -0,0 +1,158 @@
+/*
+ * HID driver for some cypress "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define CP_RDESC_SWAPPED_MIN_MAX 0x01
+#define CP_2WHEEL_MOUSE_HACK 0x02
+#define CP_2WHEEL_MOUSE_HACK_ON 0x04
+
+/*
+ * Some USB barcode readers from cypress have usage min and usage max in
+ * the wrong order
+ */
+static void cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ unsigned int i;
+
+ if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
+ return;
+
+ for (i = 0; i < rsize - 4; i++)
+ if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) {
+ __u8 tmp;
+
+ rdesc[i] = 0x19;
+ rdesc[i + 2] = 0x29;
+ tmp = rdesc[i + 3];
+ rdesc[i + 3] = rdesc[i + 1];
+ rdesc[i + 1] = tmp;
+ }
+}
+
+static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if (!(quirks & CP_2WHEEL_MOUSE_HACK))
+ return 0;
+
+ if (usage->type == EV_REL && usage->code == REL_WHEEL)
+ set_bit(REL_HWHEEL, *bit);
+ if (usage->hid == 0x00090005)
+ return -1;
+
+ return 0;
+}
+
+static int cp_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+ !usage->type || !(quirks & CP_2WHEEL_MOUSE_HACK))
+ return 0;
+
+ if (usage->hid == 0x00090005) {
+ if (value)
+ quirks |= CP_2WHEEL_MOUSE_HACK_ON;
+ else
+ quirks &= ~CP_2WHEEL_MOUSE_HACK_ON;
+ hid_set_drvdata(hdev, (void *)quirks);
+ return 1;
+ }
+
+ if (usage->code == REL_WHEEL && (quirks & CP_2WHEEL_MOUSE_HACK_ON)) {
+ struct input_dev *input = field->hidinput->input;
+
+ input_event(input, usage->type, REL_HWHEEL, value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ int ret;
+
+ hid_set_drvdata(hdev, (void *)quirks);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id cp_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1),
+ .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2),
+ .driver_data = CP_RDESC_SWAPPED_MIN_MAX },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
+ .driver_data = CP_2WHEEL_MOUSE_HACK },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, cp_devices);
+
+static struct hid_driver cp_driver = {
+ .name = "cypress",
+ .id_table = cp_devices,
+ .report_fixup = cp_report_fixup,
+ .input_mapped = cp_input_mapped,
+ .event = cp_event,
+ .probe = cp_probe,
+};
+
+static int cp_init(void)
+{
+ return hid_register_driver(&cp_driver);
+}
+
+static void cp_exit(void)
+{
+ hid_unregister_driver(&cp_driver);
+}
+
+module_init(cp_init);
+module_exit(cp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(cypress);
diff --git a/drivers/hid/hid-dell.c b/drivers/hid/hid-dell.c
new file mode 100644
index 00000000000..1a0d0dfc62f
--- /dev/null
+++ b/drivers/hid/hid-dell.c
@@ -0,0 +1,75 @@
+/*
+ * HID driver for some dell "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static int dell_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ usbhid_set_leds(hdev);
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id dell_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_SK8115) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, dell_devices);
+
+static struct hid_driver dell_driver = {
+ .name = "dell",
+ .id_table = dell_devices,
+ .probe = dell_probe,
+};
+
+static int dell_init(void)
+{
+ return hid_register_driver(&dell_driver);
+}
+
+static void dell_exit(void)
+{
+ hid_unregister_driver(&dell_driver);
+}
+
+module_init(dell_init);
+module_exit(dell_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(dell);
diff --git a/drivers/hid/hid-dummy.c b/drivers/hid/hid-dummy.c
new file mode 100644
index 00000000000..e148f86fb58
--- /dev/null
+++ b/drivers/hid/hid-dummy.c
@@ -0,0 +1,72 @@
+#include <linux/autoconf.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+static int __init hid_dummy_init(void)
+{
+#ifdef CONFIG_HID_A4TECH_MODULE
+ HID_COMPAT_CALL_DRIVER(a4tech);
+#endif
+#ifdef CONFIG_HID_APPLE_MODULE
+ HID_COMPAT_CALL_DRIVER(apple);
+#endif
+#ifdef CONFIG_HID_BELKIN_MODULE
+ HID_COMPAT_CALL_DRIVER(belkin);
+#endif
+#ifdef CONFIG_HID_BRIGHT_MODULE
+ HID_COMPAT_CALL_DRIVER(bright);
+#endif
+#ifdef CONFIG_HID_CHERRY_MODULE
+ HID_COMPAT_CALL_DRIVER(cherry);
+#endif
+#ifdef CONFIG_HID_CHICONY_MODULE
+ HID_COMPAT_CALL_DRIVER(chicony);
+#endif
+#ifdef CONFIG_HID_CYPRESS_MODULE
+ HID_COMPAT_CALL_DRIVER(cypress);
+#endif
+#ifdef CONFIG_HID_DELL_MODULE
+ HID_COMPAT_CALL_DRIVER(dell);
+#endif
+#ifdef CONFIG_HID_EZKEY_MODULE
+ HID_COMPAT_CALL_DRIVER(ezkey);
+#endif
+#ifdef CONFIG_HID_GYRATION_MODULE
+ HID_COMPAT_CALL_DRIVER(gyration);
+#endif
+#ifdef CONFIG_HID_LOGITECH_MODULE
+ HID_COMPAT_CALL_DRIVER(logitech);
+#endif
+#ifdef CONFIG_HID_MICROSOFT_MODULE
+ HID_COMPAT_CALL_DRIVER(microsoft);
+#endif
+#ifdef CONFIG_HID_MONTEREY_MODULE
+ HID_COMPAT_CALL_DRIVER(monterey);
+#endif
+#ifdef CONFIG_HID_PANTHERLORD_MODULE
+ HID_COMPAT_CALL_DRIVER(pantherlord);
+#endif
+#ifdef CONFIG_HID_PETALYNX_MODULE
+ HID_COMPAT_CALL_DRIVER(petalynx);
+#endif
+#ifdef CONFIG_HID_SAMSUNG_MODULE
+ HID_COMPAT_CALL_DRIVER(samsung);
+#endif
+#ifdef CONFIG_HID_SONY_MODULE
+ HID_COMPAT_CALL_DRIVER(sony);
+#endif
+#ifdef CONFIG_HID_SUNPLUS_MODULE
+ HID_COMPAT_CALL_DRIVER(sunplus);
+#endif
+#ifdef CONFIG_THRUSTMASTER_FF_MODULE
+ HID_COMPAT_CALL_DRIVER(thrustmaster);
+#endif
+#ifdef CONFIG_ZEROPLUS_FF_MODULE
+ HID_COMPAT_CALL_DRIVER(zeroplus);
+#endif
+
+ return -EIO;
+}
+module_init(hid_dummy_init);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-ezkey.c b/drivers/hid/hid-ezkey.c
new file mode 100644
index 00000000000..deb42f931b7
--- /dev/null
+++ b/drivers/hid/hid-ezkey.c
@@ -0,0 +1,95 @@
+/*
+ * HID driver for some ezkey "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define ez_map_rel(c) hid_map_usage(hi, usage, bit, max, EV_REL, (c))
+#define ez_map_key(c) hid_map_usage(hi, usage, bit, max, EV_KEY, (c))
+
+static int ez_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x230: ez_map_key(BTN_MOUSE); break;
+ case 0x231: ez_map_rel(REL_WHEEL); break;
+ /*
+ * this keyboard has a scrollwheel implemented in
+ * totally broken way. We map this usage temporarily
+ * to HWHEEL and handle it in the event quirk handler
+ */
+ case 0x232: ez_map_rel(REL_HWHEEL); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int ez_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+ !usage->type)
+ return 0;
+
+ /* handle the temporary quirky mapping to HWHEEL */
+ if (usage->type == EV_REL && usage->code == REL_HWHEEL) {
+ struct input_dev *input = field->hidinput->input;
+ input_event(input, usage->type, REL_WHEEL, -value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct hid_device_id ez_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ez_devices);
+
+static struct hid_driver ez_driver = {
+ .name = "ezkey",
+ .id_table = ez_devices,
+ .input_mapping = ez_input_mapping,
+ .event = ez_event,
+};
+
+static int ez_init(void)
+{
+ return hid_register_driver(&ez_driver);
+}
+
+static void ez_exit(void)
+{
+ hid_unregister_driver(&ez_driver);
+}
+
+module_init(ez_init);
+module_exit(ez_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(ezkey);
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
new file mode 100644
index 00000000000..ac5120f542c
--- /dev/null
+++ b/drivers/hid/hid-gyration.c
@@ -0,0 +1,96 @@
+/*
+ * HID driver for some gyration "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define gy_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+ return 0;
+
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ /* Reported on Gyration MCE Remote */
+ case 0x00d: gy_map_key_clear(KEY_HOME); break;
+ case 0x024: gy_map_key_clear(KEY_DVD); break;
+ case 0x025: gy_map_key_clear(KEY_PVR); break;
+ case 0x046: gy_map_key_clear(KEY_MEDIA); break;
+ case 0x047: gy_map_key_clear(KEY_MP3); break;
+ case 0x049: gy_map_key_clear(KEY_CAMERA); break;
+ case 0x04a: gy_map_key_clear(KEY_VIDEO); break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int gyration_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct input_dev *input = field->hidinput->input;
+
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
+ (usage->hid & 0xff) == 0x82) {
+ input_event(input, usage->type, usage->code, 1);
+ input_sync(input);
+ input_event(input, usage->type, usage->code, 0);
+ input_sync(input);
+ return 1;
+ }
+
+ return 0;
+}
+
+static const struct hid_device_id gyration_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, gyration_devices);
+
+static struct hid_driver gyration_driver = {
+ .name = "gyration",
+ .id_table = gyration_devices,
+ .input_mapping = gyration_input_mapping,
+ .event = gyration_event,
+};
+
+static int gyration_init(void)
+{
+ return hid_register_driver(&gyration_driver);
+}
+
+static void gyration_exit(void)
+{
+ hid_unregister_driver(&gyration_driver);
+}
+
+module_init(gyration_init);
+module_exit(gyration_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(gyration);
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
new file mode 100644
index 00000000000..aad9ed1b406
--- /dev/null
+++ b/drivers/hid/hid-ids.h
@@ -0,0 +1,404 @@
+/*
+ * USB HID quirks support for Linux
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ */
+
+/*
+ * 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 HID_IDS_H_FILE
+#define HID_IDS_H_FILE
+
+#define USB_VENDOR_ID_A4TECH 0x09da
+#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
+#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
+
+#define USB_VENDOR_ID_AASHIMA 0x06d6
+#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
+#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
+
+#define USB_VENDOR_ID_ACECAD 0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
+#define USB_DEVICE_ID_ACECAD_302 0x0008
+
+#define USB_VENDOR_ID_ADS_TECH 0x06e1
+#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
+
+#define USB_VENDOR_ID_AFATECH 0x15a4
+#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
+
+#define USB_VENDOR_ID_AIPTEK 0x08ca
+#define USB_DEVICE_ID_AIPTEK_01 0x0001
+#define USB_DEVICE_ID_AIPTEK_10 0x0010
+#define USB_DEVICE_ID_AIPTEK_20 0x0020
+#define USB_DEVICE_ID_AIPTEK_21 0x0021
+#define USB_DEVICE_ID_AIPTEK_22 0x0022
+#define USB_DEVICE_ID_AIPTEK_23 0x0023
+#define USB_DEVICE_ID_AIPTEK_24 0x0024
+
+#define USB_VENDOR_ID_AIRCABLE 0x16CA
+#define USB_DEVICE_ID_AIRCABLE1 0x1502
+
+#define USB_VENDOR_ID_ALCOR 0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
+
+#define USB_VENDOR_ID_ALPS 0x0433
+#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
+
+#define USB_VENDOR_ID_APPLE 0x05ac
+#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
+#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
+#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
+#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
+#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
+#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
+#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
+#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
+#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
+#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
+#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220
+#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221
+#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
+#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
+#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
+#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
+#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
+#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
+#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
+#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
+#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
+#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
+
+#define USB_VENDOR_ID_ASUS 0x0b05
+#define USB_DEVICE_ID_ASUS_LCM 0x1726
+
+#define USB_VENDOR_ID_ATEN 0x0557
+#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
+#define USB_DEVICE_ID_ATEN_CS124U 0x2202
+#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
+#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
+#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
+
+#define USB_VENDOR_ID_AVERMEDIA 0x07ca
+#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
+
+#define USB_VENDOR_ID_BELKIN 0x050d
+#define USB_DEVICE_ID_FLIP_KVM 0x3201
+
+#define USB_VENDOR_ID_BRIGHT 0x1241
+#define USB_DEVICE_ID_BRIGHT_ABNT2 0x1503
+
+#define USB_VENDOR_ID_BERKSHIRE 0x0c98
+#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+
+#define USB_VENDOR_ID_CHERRY 0x046a
+#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
+
+#define USB_VENDOR_ID_CHIC 0x05fe
+#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
+
+#define USB_VENDOR_ID_CHICONY 0x04f2
+#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
+
+#define USB_VENDOR_ID_CIDC 0x1677
+
+#define USB_VENDOR_ID_CMEDIA 0x0d8c
+#define USB_DEVICE_ID_CM109 0x000e
+
+#define USB_VENDOR_ID_CODEMERCS 0x07c0
+#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
+#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
+
+#define USB_VENDOR_ID_CYGNAL 0x10c4
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
+
+#define USB_VENDOR_ID_CYPRESS 0x04b4
+#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
+#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
+#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
+#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
+#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
+
+#define USB_VENDOR_ID_DELL 0x413c
+#define USB_DEVICE_ID_DELL_W7658 0x2005
+#define USB_DEVICE_ID_DELL_SK8115 0x2105
+
+#define USB_VENDOR_ID_DELORME 0x1163
+#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
+#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
+
+#define USB_VENDOR_ID_DMI 0x0c0b
+#define USB_DEVICE_ID_DMI_ENC 0x5fab
+
+#define USB_VENDOR_ID_ELO 0x04E7
+#define USB_DEVICE_ID_ELO_TS2700 0x0020
+
+#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
+#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
+
+#define USB_VENDOR_ID_EZKEY 0x0518
+#define USB_DEVICE_ID_BTC_8193 0x0002
+
+#define USB_VENDOR_ID_GAMERON 0x0810
+#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
+
+#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
+#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
+#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
+#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
+
+#define USB_VENDOR_ID_GOTOP 0x08f2
+#define USB_DEVICE_ID_SUPER_Q2 0x007f
+#define USB_DEVICE_ID_GOGOPEN 0x00ce
+#define USB_DEVICE_ID_PENPOWER 0x00f4
+
+#define USB_VENDOR_ID_GREENASIA 0x0e8f
+
+#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
+#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005
+
+#define USB_VENDOR_ID_GRIFFIN 0x077d
+#define USB_DEVICE_ID_POWERMATE 0x0410
+#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
+
+#define USB_VENDOR_ID_GTCO 0x078c
+#define USB_DEVICE_ID_GTCO_90 0x0090
+#define USB_DEVICE_ID_GTCO_100 0x0100
+#define USB_DEVICE_ID_GTCO_101 0x0101
+#define USB_DEVICE_ID_GTCO_103 0x0103
+#define USB_DEVICE_ID_GTCO_104 0x0104
+#define USB_DEVICE_ID_GTCO_105 0x0105
+#define USB_DEVICE_ID_GTCO_106 0x0106
+#define USB_DEVICE_ID_GTCO_107 0x0107
+#define USB_DEVICE_ID_GTCO_108 0x0108
+#define USB_DEVICE_ID_GTCO_200 0x0200
+#define USB_DEVICE_ID_GTCO_201 0x0201
+#define USB_DEVICE_ID_GTCO_202 0x0202
+#define USB_DEVICE_ID_GTCO_203 0x0203
+#define USB_DEVICE_ID_GTCO_204 0x0204
+#define USB_DEVICE_ID_GTCO_205 0x0205
+#define USB_DEVICE_ID_GTCO_206 0x0206
+#define USB_DEVICE_ID_GTCO_207 0x0207
+#define USB_DEVICE_ID_GTCO_300 0x0300
+#define USB_DEVICE_ID_GTCO_301 0x0301
+#define USB_DEVICE_ID_GTCO_302 0x0302
+#define USB_DEVICE_ID_GTCO_303 0x0303
+#define USB_DEVICE_ID_GTCO_304 0x0304
+#define USB_DEVICE_ID_GTCO_305 0x0305
+#define USB_DEVICE_ID_GTCO_306 0x0306
+#define USB_DEVICE_ID_GTCO_307 0x0307
+#define USB_DEVICE_ID_GTCO_308 0x0308
+#define USB_DEVICE_ID_GTCO_309 0x0309
+#define USB_DEVICE_ID_GTCO_400 0x0400
+#define USB_DEVICE_ID_GTCO_401 0x0401
+#define USB_DEVICE_ID_GTCO_402 0x0402
+#define USB_DEVICE_ID_GTCO_403 0x0403
+#define USB_DEVICE_ID_GTCO_404 0x0404
+#define USB_DEVICE_ID_GTCO_405 0x0405
+#define USB_DEVICE_ID_GTCO_500 0x0500
+#define USB_DEVICE_ID_GTCO_501 0x0501
+#define USB_DEVICE_ID_GTCO_502 0x0502
+#define USB_DEVICE_ID_GTCO_503 0x0503
+#define USB_DEVICE_ID_GTCO_504 0x0504
+#define USB_DEVICE_ID_GTCO_1000 0x1000
+#define USB_DEVICE_ID_GTCO_1001 0x1001
+#define USB_DEVICE_ID_GTCO_1002 0x1002
+#define USB_DEVICE_ID_GTCO_1003 0x1003
+#define USB_DEVICE_ID_GTCO_1004 0x1004
+#define USB_DEVICE_ID_GTCO_1005 0x1005
+#define USB_DEVICE_ID_GTCO_1006 0x1006
+#define USB_DEVICE_ID_GTCO_1007 0x1007
+
+#define USB_VENDOR_ID_GYRATION 0x0c16
+#define USB_DEVICE_ID_GYRATION_REMOTE 0x0002
+
+#define USB_VENDOR_ID_HAPP 0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
+#define USB_DEVICE_ID_UGCI_FLYING 0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
+
+#define USB_VENDOR_ID_IMATION 0x0718
+#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+
+#define USB_VENDOR_ID_KBGEAR 0x084e
+#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
+
+#define USB_VENDOR_ID_LABTEC 0x1020
+#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+
+#define USB_VENDOR_ID_LD 0x0f11
+#define USB_DEVICE_ID_LD_CASSY 0x1000
+#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
+#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
+#define USB_DEVICE_ID_LD_JWM 0x1080
+#define USB_DEVICE_ID_LD_DMMP 0x1081
+#define USB_DEVICE_ID_LD_UMIP 0x1090
+#define USB_DEVICE_ID_LD_XRAY1 0x1100
+#define USB_DEVICE_ID_LD_XRAY2 0x1101
+#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
+#define USB_DEVICE_ID_LD_COM3LAB 0x2000
+#define USB_DEVICE_ID_LD_TELEPORT 0x2010
+#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
+#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
+
+#define USB_VENDOR_ID_LOGITECH 0x046d
+#define USB_DEVICE_ID_LOGITECH_LX3 0xc044
+#define USB_DEVICE_ID_LOGITECH_V150 0xc047
+#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
+#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
+#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211
+#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
+#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
+#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
+#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
+#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
+#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
+#define USB_DEVICE_ID_LOGITECH_KBD 0xc311
+#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
+#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
+#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
+#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
+#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
+#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
+#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
+#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03
+
+#define USB_VENDOR_ID_MCC 0x09db
+#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
+#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
+
+#define USB_VENDOR_ID_MGE 0x0463
+#define USB_DEVICE_ID_MGE_UPS 0xffff
+#define USB_DEVICE_ID_MGE_UPS1 0x0001
+
+#define USB_VENDOR_ID_MICROCHIP 0x04d8
+#define USB_DEVICE_ID_PICKIT1 0x0032
+#define USB_DEVICE_ID_PICKIT2 0x0033
+
+#define USB_VENDOR_ID_MICROSOFT 0x045e
+#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
+#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
+#define USB_DEVICE_ID_MS_NE4K 0x00db
+#define USB_DEVICE_ID_MS_LK6K 0x00f9
+#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
+#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
+
+
+#define USB_VENDOR_ID_MONTEREY 0x0566
+#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
+
+#define USB_VENDOR_ID_NCR 0x0404
+#define USB_DEVICE_ID_NCR_FIRST 0x0300
+#define USB_DEVICE_ID_NCR_LAST 0x03ff
+
+#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
+#define USB_DEVICE_ID_N_S_HARMONY 0xc359
+
+#define USB_VENDOR_ID_NATSU 0x08b7
+#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
+
+#define USB_VENDOR_ID_NEC 0x073e
+#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
+
+#define USB_VENDOR_ID_ONTRAK 0x0a07
+#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
+
+#define USB_VENDOR_ID_PANJIT 0x134c
+
+#define USB_VENDOR_ID_PANTHERLORD 0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
+
+#define USB_VENDOR_ID_PETALYNX 0x18b1
+#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
+
+#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
+#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
+
+#define USB_VENDOR_ID_SAITEK 0x06a3
+#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
+
+#define USB_VENDOR_ID_SAMSUNG 0x0419
+#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
+
+#define USB_VENDOR_ID_SONY 0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
+
+#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
+#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038
+
+#define USB_VENDOR_ID_SUN 0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
+
+#define USB_VENDOR_ID_SUNPLUS 0x04fc
+#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
+
+#define USB_VENDOR_ID_TENX 0x1130
+#define USB_DEVICE_ID_TENX_IBUDDY1 0x0001
+#define USB_DEVICE_ID_TENX_IBUDDY2 0x0002
+
+#define USB_VENDOR_ID_THRUSTMASTER 0x044f
+
+#define USB_VENDOR_ID_TOPMAX 0x0663
+#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
+
+#define USB_VENDOR_ID_TURBOX 0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+
+#define USB_VENDOR_ID_VERNIER 0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
+
+#define USB_VENDOR_ID_WACOM 0x056a
+
+#define USB_VENDOR_ID_WISEGROUP 0x0925
+#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
+#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
+#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800
+#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
+
+#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666
+#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677
+#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
+
+#define USB_VENDOR_ID_YEALINK 0x6993
+#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+
+#define USB_VENDOR_ID_ZEROPLUS 0x0c12
+
+#define USB_VENDOR_ID_KYE 0x0458
+#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
+
+#endif
diff --git a/drivers/hid/hid-input-quirks.c b/drivers/hid/hid-input-quirks.c
deleted file mode 100644
index 16feea01449..00000000000
--- a/drivers/hid/hid-input-quirks.c
+++ /dev/null
@@ -1,484 +0,0 @@
-/*
- * HID-input usage mapping quirks
- *
- * This is used to handle HID-input mappings for devices violating
- * HUT 1.12 specification.
- *
- * Copyright (c) 2007-2008 Jiri Kosina
- */
-
-/*
- * 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
- */
-
-#include <linux/input.h>
-#include <linux/hid.h>
-
-#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; *bit = input->absbit; *max = ABS_MAX; } while (0)
-#define map_rel(c) do { usage->code = c; usage->type = EV_REL; *bit = input->relbit; *max = REL_MAX; } while (0)
-#define map_key(c) do { usage->code = c; usage->type = EV_KEY; *bit = input->keybit; *max = KEY_MAX; } while (0)
-#define map_led(c) do { usage->code = c; usage->type = EV_LED; *bit = input->ledbit; *max = LED_MAX; } while (0)
-
-#define map_abs_clear(c) do { map_abs(c); clear_bit(c, *bit); } while (0)
-#define map_key_clear(c) do { map_key(c); clear_bit(c, *bit); } while (0)
-
-static int quirk_belkin_wkbd(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x03a: map_key_clear(KEY_SOUND); break;
- case 0x03b: map_key_clear(KEY_CAMERA); break;
- case 0x03c: map_key_clear(KEY_DOCUMENTS); break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_cherry_cymotion(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x301: map_key_clear(KEY_PROG1); break;
- case 0x302: map_key_clear(KEY_PROG2); break;
- case 0x303: map_key_clear(KEY_PROG3); break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_logitech_ultrax_remote(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
- return 0;
-
- set_bit(EV_REP, input->evbit);
- switch(usage->hid & HID_USAGE) {
- /* Reported on Logitech Ultra X Media Remote */
- case 0x004: map_key_clear(KEY_AGAIN); break;
- case 0x00d: map_key_clear(KEY_HOME); break;
- case 0x024: map_key_clear(KEY_SHUFFLE); break;
- case 0x025: map_key_clear(KEY_TV); break;
- case 0x026: map_key_clear(KEY_MENU); break;
- case 0x031: map_key_clear(KEY_AUDIO); break;
- case 0x032: map_key_clear(KEY_TEXT); break;
- case 0x033: map_key_clear(KEY_LAST); break;
- case 0x047: map_key_clear(KEY_MP3); break;
- case 0x048: map_key_clear(KEY_DVD); break;
- case 0x049: map_key_clear(KEY_MEDIA); break;
- case 0x04a: map_key_clear(KEY_VIDEO); break;
- case 0x04b: map_key_clear(KEY_ANGLE); break;
- case 0x04c: map_key_clear(KEY_LANGUAGE); break;
- case 0x04d: map_key_clear(KEY_SUBTITLE); break;
- case 0x051: map_key_clear(KEY_RED); break;
- case 0x052: map_key_clear(KEY_CLOSE); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_gyration_remote(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
- return 0;
-
- set_bit(EV_REP, input->evbit);
- switch(usage->hid & HID_USAGE) {
- /* Reported on Gyration MCE Remote */
- case 0x00d: map_key_clear(KEY_HOME); break;
- case 0x024: map_key_clear(KEY_DVD); break;
- case 0x025: map_key_clear(KEY_PVR); break;
- case 0x046: map_key_clear(KEY_MEDIA); break;
- case 0x047: map_key_clear(KEY_MP3); break;
- case 0x049: map_key_clear(KEY_CAMERA); break;
- case 0x04a: map_key_clear(KEY_VIDEO); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_chicony_tactical_pad(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
- return 0;
-
- set_bit(EV_REP, input->evbit);
- switch (usage->hid & HID_USAGE) {
- case 0xff01: map_key_clear(BTN_1); break;
- case 0xff02: map_key_clear(BTN_2); break;
- case 0xff03: map_key_clear(BTN_3); break;
- case 0xff04: map_key_clear(BTN_4); break;
- case 0xff05: map_key_clear(BTN_5); break;
- case 0xff06: map_key_clear(BTN_6); break;
- case 0xff07: map_key_clear(BTN_7); break;
- case 0xff08: map_key_clear(BTN_8); break;
- case 0xff09: map_key_clear(BTN_9); break;
- case 0xff0a: map_key_clear(BTN_A); break;
- case 0xff0b: map_key_clear(BTN_B); break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_microsoft_ergonomy_kb(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
- return 0;
-
- switch(usage->hid & HID_USAGE) {
- case 0xfd06: map_key_clear(KEY_CHAT); break;
- case 0xfd07: map_key_clear(KEY_PHONE); break;
- case 0xff05:
- set_bit(EV_REP, input->evbit);
- map_key_clear(KEY_F13);
- set_bit(KEY_F14, input->keybit);
- set_bit(KEY_F15, input->keybit);
- set_bit(KEY_F16, input->keybit);
- set_bit(KEY_F17, input->keybit);
- set_bit(KEY_F18, input->keybit);
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_microsoft_presenter_8k(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
- return 0;
-
- set_bit(EV_REP, input->evbit);
- switch(usage->hid & HID_USAGE) {
- case 0xfd08: map_key_clear(KEY_FORWARD); break;
- case 0xfd09: map_key_clear(KEY_BACK); break;
- case 0xfd0b: map_key_clear(KEY_PLAYPAUSE); break;
- case 0xfd0e: map_key_clear(KEY_CLOSE); break;
- case 0xfd0f: map_key_clear(KEY_PLAY); break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_petalynx_remote(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if (((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR) &&
- ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER))
- return 0;
-
- if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR)
- switch(usage->hid & HID_USAGE) {
- case 0x05a: map_key_clear(KEY_TEXT); break;
- case 0x05b: map_key_clear(KEY_RED); break;
- case 0x05c: map_key_clear(KEY_GREEN); break;
- case 0x05d: map_key_clear(KEY_YELLOW); break;
- case 0x05e: map_key_clear(KEY_BLUE); break;
- default:
- return 0;
- }
-
- if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER)
- switch(usage->hid & HID_USAGE) {
- case 0x0f6: map_key_clear(KEY_NEXT); break;
- case 0x0fa: map_key_clear(KEY_BACK); break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_logitech_wireless(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x1001: map_key_clear(KEY_MESSENGER); break;
- case 0x1003: map_key_clear(KEY_SOUND); break;
- case 0x1004: map_key_clear(KEY_VIDEO); break;
- case 0x1005: map_key_clear(KEY_AUDIO); break;
- case 0x100a: map_key_clear(KEY_DOCUMENTS); break;
- case 0x1011: map_key_clear(KEY_PREVIOUSSONG); break;
- case 0x1012: map_key_clear(KEY_NEXTSONG); break;
- case 0x1013: map_key_clear(KEY_CAMERA); break;
- case 0x1014: map_key_clear(KEY_MESSENGER); break;
- case 0x1015: map_key_clear(KEY_RECORD); break;
- case 0x1016: map_key_clear(KEY_PLAYER); break;
- case 0x1017: map_key_clear(KEY_EJECTCD); break;
- case 0x1018: map_key_clear(KEY_MEDIA); break;
- case 0x1019: map_key_clear(KEY_PROG1); break;
- case 0x101a: map_key_clear(KEY_PROG2); break;
- case 0x101b: map_key_clear(KEY_PROG3); break;
- case 0x101f: map_key_clear(KEY_ZOOMIN); break;
- case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
- case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
- case 0x1023: map_key_clear(KEY_CLOSE); break;
- case 0x1027: map_key_clear(KEY_MENU); break;
- /* this one is marked as 'Rotate' */
- case 0x1028: map_key_clear(KEY_ANGLE); break;
- case 0x1029: map_key_clear(KEY_SHUFFLE); break;
- case 0x102a: map_key_clear(KEY_BACK); break;
- case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break;
- case 0x1041: map_key_clear(KEY_BATTERY); break;
- case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break;
- case 0x1043: map_key_clear(KEY_SPREADSHEET); break;
- case 0x1044: map_key_clear(KEY_PRESENTATION); break;
- case 0x1045: map_key_clear(KEY_UNDO); break;
- case 0x1046: map_key_clear(KEY_REDO); break;
- case 0x1047: map_key_clear(KEY_PRINT); break;
- case 0x1048: map_key_clear(KEY_SAVE); break;
- case 0x1049: map_key_clear(KEY_PROG1); break;
- case 0x104a: map_key_clear(KEY_PROG2); break;
- case 0x104b: map_key_clear(KEY_PROG3); break;
- case 0x104c: map_key_clear(KEY_PROG4); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_cherry_genius_29e(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x156: map_key_clear(KEY_WORDPROCESSOR); break;
- case 0x157: map_key_clear(KEY_SPREADSHEET); break;
- case 0x158: map_key_clear(KEY_PRESENTATION); break;
- case 0x15c: map_key_clear(KEY_STOP); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_btc_8193(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x230: map_key(BTN_MOUSE); break;
- case 0x231: map_rel(REL_WHEEL); break;
- /*
- * this keyboard has a scrollwheel implemented in
- * totally broken way. We map this usage temporarily
- * to HWHEEL and handle it in the event quirk handler
- */
- case 0x232: map_rel(REL_HWHEEL); break;
-
- default:
- return 0;
- }
- return 1;
-}
-
-static int quirk_sunplus_wdesktop(struct hid_usage *usage, struct input_dev *input,
- unsigned long **bit, int *max)
-{
- if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
- return 0;
-
- switch (usage->hid & HID_USAGE) {
- case 0x2003: map_key_clear(KEY_ZOOMIN); break;
- case 0x2103: map_key_clear(KEY_ZOOMOUT); break;
- default:
- return 0;
- }
- return 1;
-}
-
-#define VENDOR_ID_BELKIN 0x1020
-#define DEVICE_ID_BELKIN_WIRELESS_KEYBOARD 0x0006
-
-#define VENDOR_ID_CHERRY 0x046a
-#define DEVICE_ID_CHERRY_CYMOTION 0x0023
-
-#define VENDOR_ID_CHICONY 0x04f2
-#define DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
-
-#define VENDOR_ID_EZKEY 0x0518
-#define DEVICE_ID_BTC_8193 0x0002
-
-#define VENDOR_ID_GYRATION 0x0c16
-#define DEVICE_ID_GYRATION_REMOTE 0x0002
-
-#define VENDOR_ID_LOGITECH 0x046d
-#define DEVICE_ID_LOGITECH_RECEIVER 0xc101
-#define DEVICE_ID_S510_RECEIVER 0xc50c
-#define DEVICE_ID_S510_RECEIVER_2 0xc517
-#define DEVICE_ID_MX3000_RECEIVER 0xc513
-
-#define VENDOR_ID_MICROSOFT 0x045e
-#define DEVICE_ID_MS4K 0x00db
-#define DEVICE_ID_MS6K 0x00f9
-#define DEVICE_IS_MS_PRESENTER_8K_BT 0x0701
-#define DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
-
-#define VENDOR_ID_MONTEREY 0x0566
-#define DEVICE_ID_GENIUS_KB29E 0x3004
-
-#define VENDOR_ID_PETALYNX 0x18b1
-#define DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
-
-#define VENDOR_ID_SUNPLUS 0x04fc
-#define DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
-
-static const struct hid_input_blacklist {
- __u16 idVendor;
- __u16 idProduct;
- int (*quirk)(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-} hid_input_blacklist[] = {
- { VENDOR_ID_BELKIN, DEVICE_ID_BELKIN_WIRELESS_KEYBOARD, quirk_belkin_wkbd },
-
- { VENDOR_ID_CHERRY, DEVICE_ID_CHERRY_CYMOTION, quirk_cherry_cymotion },
-
- { VENDOR_ID_CHICONY, DEVICE_ID_CHICONY_TACTICAL_PAD, quirk_chicony_tactical_pad },
-
- { VENDOR_ID_EZKEY, DEVICE_ID_BTC_8193, quirk_btc_8193 },
-
- { VENDOR_ID_GYRATION, DEVICE_ID_GYRATION_REMOTE, quirk_gyration_remote },
-
- { VENDOR_ID_LOGITECH, DEVICE_ID_LOGITECH_RECEIVER, quirk_logitech_ultrax_remote },
- { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER, quirk_logitech_wireless },
- { VENDOR_ID_LOGITECH, DEVICE_ID_S510_RECEIVER_2, quirk_logitech_wireless },
- { VENDOR_ID_LOGITECH, DEVICE_ID_MX3000_RECEIVER, quirk_logitech_wireless },
-
- { VENDOR_ID_MICROSOFT, DEVICE_ID_MS4K, quirk_microsoft_ergonomy_kb },
- { VENDOR_ID_MICROSOFT, DEVICE_ID_MS6K, quirk_microsoft_ergonomy_kb },
- { VENDOR_ID_MICROSOFT, DEVICE_IS_MS_PRESENTER_8K_BT, quirk_microsoft_presenter_8k },
- { VENDOR_ID_MICROSOFT, DEVICE_ID_MS_PRESENTER_8K_USB, quirk_microsoft_presenter_8k },
-
- { VENDOR_ID_MONTEREY, DEVICE_ID_GENIUS_KB29E, quirk_cherry_genius_29e },
-
- { VENDOR_ID_PETALYNX, DEVICE_ID_PETALYNX_MAXTER_REMOTE, quirk_petalynx_remote },
-
- { VENDOR_ID_SUNPLUS, DEVICE_ID_SUNPLUS_WDESKTOP, quirk_sunplus_wdesktop },
-
- { 0, 0, NULL }
-};
-
-int hidinput_mapping_quirks(struct hid_usage *usage,
- struct input_dev *input,
- unsigned long **bit, int *max)
-{
- struct hid_device *device = input_get_drvdata(input);
- int i = 0;
-
- while (hid_input_blacklist[i].quirk) {
- if (hid_input_blacklist[i].idVendor == device->vendor &&
- hid_input_blacklist[i].idProduct == device->product)
- return hid_input_blacklist[i].quirk(usage, input, bit, max);
- i++;
- }
- return 0;
-}
-
-int hidinput_event_quirks(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
-{
- struct input_dev *input;
-
- input = field->hidinput->input;
-
- if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
- || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) {
- if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
- else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON;
- return 1;
- }
-
- if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
- (usage->type == EV_REL) &&
- (usage->code == REL_WHEEL)) {
- hid->delayed_value = value;
- return 1;
- }
-
- if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_B8) &&
- (usage->hid == 0x000100b8)) {
- input_event(input, EV_REL, value ? REL_HWHEEL : REL_WHEEL, hid->delayed_value);
- return 1;
- }
-
- if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) {
- input_event(input, usage->type, usage->code, -value);
- return 1;
- }
-
- if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) {
- input_event(input, usage->type, REL_HWHEEL, value);
- return 1;
- }
-
- if ((hid->quirks & HID_QUIRK_APPLE_HAS_FN) && hidinput_apple_event(hid, input, usage, value))
- return 1;
-
- /* Handling MS keyboards special buttons */
- if (hid->quirks & HID_QUIRK_MICROSOFT_KEYS &&
- usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
- int key = 0;
- static int last_key = 0;
- switch (value) {
- case 0x01: key = KEY_F14; break;
- case 0x02: key = KEY_F15; break;
- case 0x04: key = KEY_F16; break;
- case 0x08: key = KEY_F17; break;
- case 0x10: key = KEY_F18; break;
- default: break;
- }
- if (key) {
- input_event(input, usage->type, key, 1);
- last_key = key;
- } else {
- input_event(input, usage->type, last_key, 0);
- }
- }
-
- /* handle the temporary quirky mapping to HWHEEL */
- if (hid->quirks & HID_QUIRK_HWHEEL_WHEEL_INVERT &&
- usage->type == EV_REL && usage->code == REL_HWHEEL) {
- input_event(input, usage->type, REL_WHEEL, -value);
- return 1;
- }
-
- /* Gyration MCE remote "Sleep" key */
- if (hid->vendor == VENDOR_ID_GYRATION &&
- hid->product == DEVICE_ID_GYRATION_REMOTE &&
- (usage->hid & HID_USAGE_PAGE) == HID_UP_GENDESK &&
- (usage->hid & 0xff) == 0x82) {
- input_event(input, usage->type, usage->code, 1);
- input_sync(input);
- input_event(input, usage->type, usage->code, 0);
- input_sync(input);
- return 1;
- }
- return 0;
-}
-
-
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 1b2e8dc3398..7f183b7147e 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -32,11 +32,6 @@
#include <linux/hid.h>
#include <linux/hid-debug.h>
-static int hid_apple_fnmode = 1;
-module_param_named(pb_fnmode, hid_apple_fnmode, int, 0644);
-MODULE_PARM_DESC(pb_fnmode,
- "Mode of fn key on Apple keyboards (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)");
-
#define unk KEY_UNKNOWN
static const unsigned char hid_keyboard[256] = {
@@ -58,227 +53,20 @@ static const unsigned char hid_keyboard[256] = {
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
};
-/* extended mapping for certain Logitech hardware (Logitech cordless desktop LX500) */
-#define LOGITECH_EXPANDED_KEYMAP_SIZE 80
-static int logitech_expanded_keymap[LOGITECH_EXPANDED_KEYMAP_SIZE] = {
- 0,216, 0,213,175,156, 0, 0, 0, 0,
- 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
- 174,167,152,161,112, 0, 0, 0,154, 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, 0, 0, 0, 0,183,184,185,186,187,
- 188,189,190,191,192,193,194, 0, 0, 0
-};
-
static const struct {
__s32 x;
__s32 y;
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0)
-#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
-#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
-#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
-
-#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
-#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
-
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
-
-struct hidinput_key_translation {
- u16 from;
- u16 to;
- u8 flags;
-};
-
-#define APPLE_FLAG_FKEY 0x01
-
-static struct hidinput_key_translation apple_fn_keys[] = {
- { KEY_BACKSPACE, KEY_DELETE },
- { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
- { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
- { KEY_F3, KEY_FN_F5, APPLE_FLAG_FKEY }, /* Exposé */
- { KEY_F4, KEY_FN_F4, APPLE_FLAG_FKEY }, /* Dashboard */
- { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
- { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
- { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
- { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
- { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
- { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
- { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
- { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
- { KEY_UP, KEY_PAGEUP },
- { KEY_DOWN, KEY_PAGEDOWN },
- { KEY_LEFT, KEY_HOME },
- { KEY_RIGHT, KEY_END },
- { }
-};
-
-static struct hidinput_key_translation powerbook_fn_keys[] = {
- { KEY_BACKSPACE, KEY_DELETE },
- { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
- { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
- { KEY_F3, KEY_MUTE, APPLE_FLAG_FKEY },
- { KEY_F4, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
- { KEY_F5, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
- { KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY },
- { KEY_F7, KEY_SWITCHVIDEOMODE, APPLE_FLAG_FKEY },
- { KEY_F8, KEY_KBDILLUMTOGGLE, APPLE_FLAG_FKEY },
- { KEY_F9, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY },
- { KEY_F10, KEY_KBDILLUMUP, APPLE_FLAG_FKEY },
- { KEY_UP, KEY_PAGEUP },
- { KEY_DOWN, KEY_PAGEDOWN },
- { KEY_LEFT, KEY_HOME },
- { KEY_RIGHT, KEY_END },
- { }
-};
-
-static struct hidinput_key_translation powerbook_numlock_keys[] = {
- { KEY_J, KEY_KP1 },
- { KEY_K, KEY_KP2 },
- { KEY_L, KEY_KP3 },
- { KEY_U, KEY_KP4 },
- { KEY_I, KEY_KP5 },
- { KEY_O, KEY_KP6 },
- { KEY_7, KEY_KP7 },
- { KEY_8, KEY_KP8 },
- { KEY_9, KEY_KP9 },
- { KEY_M, KEY_KP0 },
- { KEY_DOT, KEY_KPDOT },
- { KEY_SLASH, KEY_KPPLUS },
- { KEY_SEMICOLON, KEY_KPMINUS },
- { KEY_P, KEY_KPASTERISK },
- { KEY_MINUS, KEY_KPEQUAL },
- { KEY_0, KEY_KPSLASH },
- { KEY_F6, KEY_NUMLOCK },
- { KEY_KPENTER, KEY_KPENTER },
- { KEY_BACKSPACE, KEY_BACKSPACE },
- { }
-};
-
-static struct hidinput_key_translation apple_iso_keyboard[] = {
- { KEY_GRAVE, KEY_102ND },
- { KEY_102ND, KEY_GRAVE },
- { }
-};
+#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
+#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
+#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
+#define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c))
-static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from)
-{
- struct hidinput_key_translation *trans;
-
- /* Look for the translation */
- for (trans = table; trans->from; trans++)
- if (trans->from == from)
- return trans;
-
- return NULL;
-}
-
-int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
- struct hid_usage *usage, __s32 value)
-{
- struct hidinput_key_translation *trans;
-
- if (usage->code == KEY_FN) {
- if (value) hid->quirks |= HID_QUIRK_APPLE_FN_ON;
- else hid->quirks &= ~HID_QUIRK_APPLE_FN_ON;
-
- input_event(input, usage->type, usage->code, value);
-
- return 1;
- }
-
- if (hid_apple_fnmode) {
- int do_translate;
-
- trans = find_translation((hid->product < 0x220 ||
- hid->product >= 0x300) ?
- powerbook_fn_keys : apple_fn_keys,
- usage->code);
- if (trans) {
- if (test_bit(usage->code, hid->apple_pressed_fn))
- do_translate = 1;
- else if (trans->flags & APPLE_FLAG_FKEY)
- do_translate =
- (hid_apple_fnmode == 2 && (hid->quirks & HID_QUIRK_APPLE_FN_ON)) ||
- (hid_apple_fnmode == 1 && !(hid->quirks & HID_QUIRK_APPLE_FN_ON));
- else
- do_translate = (hid->quirks & HID_QUIRK_APPLE_FN_ON);
-
- if (do_translate) {
- if (value)
- set_bit(usage->code, hid->apple_pressed_fn);
- else
- clear_bit(usage->code, hid->apple_pressed_fn);
-
- input_event(input, usage->type, trans->to, value);
-
- return 1;
- }
- }
-
- if (hid->quirks & HID_QUIRK_APPLE_NUMLOCK_EMULATION && (
- test_bit(usage->code, hid->pb_pressed_numlock) ||
- test_bit(LED_NUML, input->led))) {
- trans = find_translation(powerbook_numlock_keys, usage->code);
-
- if (trans) {
- if (value)
- set_bit(usage->code, hid->pb_pressed_numlock);
- else
- clear_bit(usage->code, hid->pb_pressed_numlock);
-
- input_event(input, usage->type, trans->to, value);
- }
-
- return 1;
- }
- }
-
- if (hid->quirks & HID_QUIRK_APPLE_ISO_KEYBOARD) {
- trans = find_translation(apple_iso_keyboard, usage->code);
- if (trans) {
- input_event(input, usage->type, trans->to, value);
- return 1;
- }
- }
-
- return 0;
-}
-
-static void hidinput_apple_setup(struct input_dev *input)
-{
- struct hidinput_key_translation *trans;
-
- set_bit(KEY_NUMLOCK, input->keybit);
-
- /* Enable all needed keys */
- for (trans = apple_fn_keys; trans->from; trans++)
- set_bit(trans->to, input->keybit);
-
- for (trans = powerbook_fn_keys; trans->from; trans++)
- set_bit(trans->to, input->keybit);
-
- for (trans = powerbook_numlock_keys; trans->from; trans++)
- set_bit(trans->to, input->keybit);
-
- for (trans = apple_iso_keyboard; trans->from; trans++)
- set_bit(trans->to, input->keybit);
-
-}
-#else
-inline int hidinput_apple_event(struct hid_device *hid,
- struct input_dev *input,
- struct hid_usage *usage, __s32 value)
-{
- return 0;
-}
-
-static inline void hidinput_apple_setup(struct input_dev *input)
-{
-}
-#endif
+#define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
+ &max, EV_ABS, (c))
+#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \
+ &max, EV_KEY, (c))
static inline int match_scancode(int code, int scancode)
{
@@ -366,7 +154,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
{
struct input_dev *input = hidinput->input;
struct hid_device *device = input_get_drvdata(input);
- int max = 0, code, ret;
+ int max = 0, code;
unsigned long *bit = NULL;
field->hidinput = hidinput;
@@ -385,406 +173,345 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
}
- /* handle input mappings for quirky devices */
- ret = hidinput_mapping_quirks(usage, input, &bit, &max);
- if (ret)
- goto mapped;
+ if (device->driver->input_mapping) {
+ int ret = device->driver->input_mapping(device, hidinput, field,
+ usage, &bit, &max);
+ if (ret > 0)
+ goto mapped;
+ if (ret < 0)
+ goto ignore;
+ }
switch (usage->hid & HID_USAGE_PAGE) {
+ case HID_UP_UNDEFINED:
+ goto ignore;
- case HID_UP_UNDEFINED:
- goto ignore;
-
- case HID_UP_KEYBOARD:
+ case HID_UP_KEYBOARD:
+ set_bit(EV_REP, input->evbit);
- set_bit(EV_REP, input->evbit);
+ if ((usage->hid & HID_USAGE) < 256) {
+ if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
+ map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
+ } else
+ map_key(KEY_UNKNOWN);
- if ((usage->hid & HID_USAGE) < 256) {
- if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore;
- map_key_clear(hid_keyboard[usage->hid & HID_USAGE]);
- } else
- map_key(KEY_UNKNOWN);
+ break;
- break;
+ case HID_UP_BUTTON:
+ code = ((usage->hid - 1) & 0xf);
- case HID_UP_BUTTON:
-
- code = ((usage->hid - 1) & 0xf);
-
- switch (field->application) {
- case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
- case HID_GD_JOYSTICK: code += 0x120; break;
- case HID_GD_GAMEPAD: code += 0x130; break;
- default:
- switch (field->physical) {
- case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
- case HID_GD_JOYSTICK: code += 0x120; break;
- case HID_GD_GAMEPAD: code += 0x130; break;
- default: code += 0x100;
- }
- }
-
- /* Special handling for Logitech Cordless Desktop */
- if (field->application != HID_GD_MOUSE) {
- if (device->quirks & HID_QUIRK_LOGITECH_EXPANDED_KEYMAP) {
- int hid = usage->hid & HID_USAGE;
- if (hid < LOGITECH_EXPANDED_KEYMAP_SIZE && logitech_expanded_keymap[hid] != 0)
- code = logitech_expanded_keymap[hid];
- }
- } else {
- if (device->quirks & HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL) {
- int hid = usage->hid & HID_USAGE;
- if (hid == 7 || hid == 8)
- goto ignore;
- }
+ switch (field->application) {
+ case HID_GD_MOUSE:
+ case HID_GD_POINTER: code += 0x110; break;
+ case HID_GD_JOYSTICK: code += 0x120; break;
+ case HID_GD_GAMEPAD: code += 0x130; break;
+ default:
+ switch (field->physical) {
+ case HID_GD_MOUSE:
+ case HID_GD_POINTER: code += 0x110; break;
+ case HID_GD_JOYSTICK: code += 0x120; break;
+ case HID_GD_GAMEPAD: code += 0x130; break;
+ default: code += 0x100;
}
+ }
- map_key(code);
- break;
-
-
- case HID_UP_SIMULATION:
-
- switch (usage->hid & 0xffff) {
- case 0xba: map_abs(ABS_RUDDER); break;
- case 0xbb: map_abs(ABS_THROTTLE); break;
- case 0xc4: map_abs(ABS_GAS); break;
- case 0xc5: map_abs(ABS_BRAKE); break;
- case 0xc8: map_abs(ABS_WHEEL); break;
- default: goto ignore;
+ map_key(code);
+ break;
+
+ case HID_UP_SIMULATION:
+ switch (usage->hid & 0xffff) {
+ case 0xba: map_abs(ABS_RUDDER); break;
+ case 0xbb: map_abs(ABS_THROTTLE); break;
+ case 0xc4: map_abs(ABS_GAS); break;
+ case 0xc5: map_abs(ABS_BRAKE); break;
+ case 0xc8: map_abs(ABS_WHEEL); break;
+ default: goto ignore;
+ }
+ break;
+
+ case HID_UP_GENDESK:
+ if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
+ switch (usage->hid & 0xf) {
+ case 0x1: map_key_clear(KEY_POWER); break;
+ case 0x2: map_key_clear(KEY_SLEEP); break;
+ case 0x3: map_key_clear(KEY_WAKEUP); break;
+ default: goto unknown;
}
break;
+ }
- case HID_UP_GENDESK:
-
- if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */
- switch (usage->hid & 0xf) {
- case 0x1: map_key_clear(KEY_POWER); break;
- case 0x2: map_key_clear(KEY_SLEEP); break;
- case 0x3: map_key_clear(KEY_WAKEUP); break;
- default: goto unknown;
- }
- break;
- }
-
- if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
- switch (usage->hid) {
- case HID_GD_UP: usage->hat_dir = 1; break;
- case HID_GD_DOWN: usage->hat_dir = 5; break;
- case HID_GD_RIGHT: usage->hat_dir = 3; break;
- case HID_GD_LEFT: usage->hat_dir = 7; break;
- default: goto unknown;
- }
- if (field->dpad) {
- map_abs(field->dpad);
- goto ignore;
- }
- map_abs(ABS_HAT0X);
- break;
- }
-
+ if ((usage->hid & 0xf0) == 0x90) { /* D-pad */
switch (usage->hid) {
-
- /* These usage IDs map directly to the usage codes. */
- case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
- case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
- case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
- if (field->flags & HID_MAIN_ITEM_RELATIVE)
- map_rel(usage->hid & 0xf);
- else
- map_abs(usage->hid & 0xf);
- break;
-
- case HID_GD_HATSWITCH:
- usage->hat_min = field->logical_minimum;
- usage->hat_max = field->logical_maximum;
- map_abs(ABS_HAT0X);
- break;
-
- case HID_GD_START: map_key_clear(BTN_START); break;
- case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
-
- default: goto unknown;
+ case HID_GD_UP: usage->hat_dir = 1; break;
+ case HID_GD_DOWN: usage->hat_dir = 5; break;
+ case HID_GD_RIGHT: usage->hat_dir = 3; break;
+ case HID_GD_LEFT: usage->hat_dir = 7; break;
+ default: goto unknown;
}
-
- break;
-
- case HID_UP_LED:
-
- switch (usage->hid & 0xffff) { /* HID-Value: */
- case 0x01: map_led (LED_NUML); break; /* "Num Lock" */
- case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */
- case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */
- case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */
- case 0x05: map_led (LED_KANA); break; /* "Kana" */
- case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */
- case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */
- case 0x09: map_led (LED_MUTE); break; /* "Mute" */
- case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */
- case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */
- case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */
-
- default: goto ignore;
+ if (field->dpad) {
+ map_abs(field->dpad);
+ goto ignore;
}
+ map_abs(ABS_HAT0X);
break;
+ }
- case HID_UP_DIGITIZER:
-
- switch (usage->hid & 0xff) {
-
- case 0x30: /* TipPressure */
- if (!test_bit(BTN_TOUCH, input->keybit)) {
- device->quirks |= HID_QUIRK_NOTOUCH;
- set_bit(EV_KEY, input->evbit);
- set_bit(BTN_TOUCH, input->keybit);
- }
-
- map_abs_clear(ABS_PRESSURE);
- break;
-
- case 0x32: /* InRange */
- switch (field->physical & 0xff) {
- case 0x21: map_key(BTN_TOOL_MOUSE); break;
- case 0x22: map_key(BTN_TOOL_FINGER); break;
- default: map_key(BTN_TOOL_PEN); break;
- }
- break;
+ switch (usage->hid) {
+ /* These usage IDs map directly to the usage codes. */
+ case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
+ case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
+ case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
+ if (field->flags & HID_MAIN_ITEM_RELATIVE)
+ map_rel(usage->hid & 0xf);
+ else
+ map_abs(usage->hid & 0xf);
+ break;
- case 0x3c: /* Invert */
- map_key_clear(BTN_TOOL_RUBBER);
- break;
+ case HID_GD_HATSWITCH:
+ usage->hat_min = field->logical_minimum;
+ usage->hat_max = field->logical_maximum;
+ map_abs(ABS_HAT0X);
+ break;
- case 0x33: /* Touch */
- case 0x42: /* TipSwitch */
- case 0x43: /* TipSwitch2 */
- device->quirks &= ~HID_QUIRK_NOTOUCH;
- map_key_clear(BTN_TOUCH);
- break;
+ case HID_GD_START: map_key_clear(BTN_START); break;
+ case HID_GD_SELECT: map_key_clear(BTN_SELECT); break;
- case 0x44: /* BarrelSwitch */
- map_key_clear(BTN_STYLUS);
- break;
+ default: goto unknown;
+ }
- default: goto unknown;
+ break;
+
+ case HID_UP_LED:
+ switch (usage->hid & 0xffff) { /* HID-Value: */
+ case 0x01: map_led (LED_NUML); break; /* "Num Lock" */
+ case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */
+ case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */
+ case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */
+ case 0x05: map_led (LED_KANA); break; /* "Kana" */
+ case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */
+ case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */
+ case 0x09: map_led (LED_MUTE); break; /* "Mute" */
+ case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */
+ case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */
+ case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */
+
+ default: goto ignore;
+ }
+ break;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid & 0xff) {
+ case 0x30: /* TipPressure */
+ if (!test_bit(BTN_TOUCH, input->keybit)) {
+ device->quirks |= HID_QUIRK_NOTOUCH;
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_TOUCH, input->keybit);
}
+ map_abs_clear(ABS_PRESSURE);
break;
- case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
-
- switch (usage->hid & HID_USAGE) {
- case 0x000: goto ignore;
- case 0x034: map_key_clear(KEY_SLEEP); break;
- case 0x036: map_key_clear(BTN_MISC); break;
-
- case 0x040: map_key_clear(KEY_MENU); break;
- case 0x045: map_key_clear(KEY_RADIO); break;
-
- case 0x083: map_key_clear(KEY_LAST); break;
- case 0x088: map_key_clear(KEY_PC); break;
- case 0x089: map_key_clear(KEY_TV); break;
- case 0x08a: map_key_clear(KEY_WWW); break;
- case 0x08b: map_key_clear(KEY_DVD); break;
- case 0x08c: map_key_clear(KEY_PHONE); break;
- case 0x08d: map_key_clear(KEY_PROGRAM); break;
- case 0x08e: map_key_clear(KEY_VIDEOPHONE); break;
- case 0x08f: map_key_clear(KEY_GAMES); break;
- case 0x090: map_key_clear(KEY_MEMO); break;
- case 0x091: map_key_clear(KEY_CD); break;
- case 0x092: map_key_clear(KEY_VCR); break;
- case 0x093: map_key_clear(KEY_TUNER); break;
- case 0x094: map_key_clear(KEY_EXIT); break;
- case 0x095: map_key_clear(KEY_HELP); break;
- case 0x096: map_key_clear(KEY_TAPE); break;
- case 0x097: map_key_clear(KEY_TV2); break;
- case 0x098: map_key_clear(KEY_SAT); break;
- case 0x09a: map_key_clear(KEY_PVR); break;
-
- case 0x09c: map_key_clear(KEY_CHANNELUP); break;
- case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
- case 0x0a0: map_key_clear(KEY_VCR2); break;
-
- case 0x0b0: map_key_clear(KEY_PLAY); break;
- case 0x0b1: map_key_clear(KEY_PAUSE); break;
- case 0x0b2: map_key_clear(KEY_RECORD); break;
- case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
- case 0x0b4: map_key_clear(KEY_REWIND); break;
- case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
- case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
- case 0x0b7: map_key_clear(KEY_STOPCD); break;
- case 0x0b8: map_key_clear(KEY_EJECTCD); break;
- case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break;
-
- case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
- case 0x0e0: map_abs_clear(ABS_VOLUME); break;
- case 0x0e2: map_key_clear(KEY_MUTE); break;
- case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
- case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
- case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
-
- case 0x182: map_key_clear(KEY_BOOKMARKS); break;
- case 0x183: map_key_clear(KEY_CONFIG); break;
- case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
- case 0x185: map_key_clear(KEY_EDITOR); break;
- case 0x186: map_key_clear(KEY_SPREADSHEET); break;
- case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break;
- case 0x188: map_key_clear(KEY_PRESENTATION); break;
- case 0x189: map_key_clear(KEY_DATABASE); break;
- case 0x18a: map_key_clear(KEY_MAIL); break;
- case 0x18b: map_key_clear(KEY_NEWS); break;
- case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
- case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
- case 0x18e: map_key_clear(KEY_CALENDAR); break;
- case 0x191: map_key_clear(KEY_FINANCE); break;
- case 0x192: map_key_clear(KEY_CALC); break;
- case 0x194: map_key_clear(KEY_FILE); break;
- case 0x196: map_key_clear(KEY_WWW); break;
- case 0x19c: map_key_clear(KEY_LOGOFF); break;
- case 0x19e: map_key_clear(KEY_COFFEE); break;
- case 0x1a6: map_key_clear(KEY_HELP); break;
- case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
- case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
- case 0x1b6: map_key_clear(KEY_MEDIA); break;
- case 0x1b7: map_key_clear(KEY_SOUND); break;
- case 0x1bc: map_key_clear(KEY_MESSENGER); break;
- case 0x1bd: map_key_clear(KEY_INFO); break;
- case 0x201: map_key_clear(KEY_NEW); break;
- case 0x202: map_key_clear(KEY_OPEN); break;
- case 0x203: map_key_clear(KEY_CLOSE); break;
- case 0x204: map_key_clear(KEY_EXIT); break;
- case 0x207: map_key_clear(KEY_SAVE); break;
- case 0x208: map_key_clear(KEY_PRINT); break;
- case 0x209: map_key_clear(KEY_PROPS); break;
- case 0x21a: map_key_clear(KEY_UNDO); break;
- case 0x21b: map_key_clear(KEY_COPY); break;
- case 0x21c: map_key_clear(KEY_CUT); break;
- case 0x21d: map_key_clear(KEY_PASTE); break;
- case 0x21f: map_key_clear(KEY_FIND); break;
- case 0x221: map_key_clear(KEY_SEARCH); break;
- case 0x222: map_key_clear(KEY_GOTO); break;
- case 0x223: map_key_clear(KEY_HOMEPAGE); break;
- case 0x224: map_key_clear(KEY_BACK); break;
- case 0x225: map_key_clear(KEY_FORWARD); break;
- case 0x226: map_key_clear(KEY_STOP); break;
- case 0x227: map_key_clear(KEY_REFRESH); break;
- case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
- case 0x22d: map_key_clear(KEY_ZOOMIN); break;
- case 0x22e: map_key_clear(KEY_ZOOMOUT); break;
- case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
- case 0x233: map_key_clear(KEY_SCROLLUP); break;
- case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
- case 0x238: map_rel(REL_HWHEEL); break;
- case 0x25f: map_key_clear(KEY_CANCEL); break;
- case 0x279: map_key_clear(KEY_REDO); break;
-
- case 0x289: map_key_clear(KEY_REPLY); break;
- case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
- case 0x28c: map_key_clear(KEY_SEND); break;
-
- default: goto ignore;
+ case 0x32: /* InRange */
+ switch (field->physical & 0xff) {
+ case 0x21: map_key(BTN_TOOL_MOUSE); break;
+ case 0x22: map_key(BTN_TOOL_FINGER); break;
+ default: map_key(BTN_TOOL_PEN); break;
}
break;
- case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
-
- set_bit(EV_REP, input->evbit);
- switch (usage->hid & HID_USAGE) {
- case 0x021: map_key_clear(KEY_PRINT); break;
- case 0x070: map_key_clear(KEY_HP); break;
- case 0x071: map_key_clear(KEY_CAMERA); break;
- case 0x072: map_key_clear(KEY_SOUND); break;
- case 0x073: map_key_clear(KEY_QUESTION); break;
- case 0x080: map_key_clear(KEY_EMAIL); break;
- case 0x081: map_key_clear(KEY_CHAT); break;
- case 0x082: map_key_clear(KEY_SEARCH); break;
- case 0x083: map_key_clear(KEY_CONNECT); break;
- case 0x084: map_key_clear(KEY_FINANCE); break;
- case 0x085: map_key_clear(KEY_SPORT); break;
- case 0x086: map_key_clear(KEY_SHOP); break;
- default: goto ignore;
- }
+ case 0x3c: /* Invert */
+ map_key_clear(BTN_TOOL_RUBBER);
break;
- case HID_UP_MSVENDOR:
-
- goto ignore;
-
- case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
-
- set_bit(EV_REP, input->evbit);
- switch(usage->hid & HID_USAGE) {
- case 0x003:
- /* The fn key on Apple USB keyboards */
- map_key_clear(KEY_FN);
- hidinput_apple_setup(input);
- break;
+ case 0x33: /* Touch */
+ case 0x42: /* TipSwitch */
+ case 0x43: /* TipSwitch2 */
+ device->quirks &= ~HID_QUIRK_NOTOUCH;
+ map_key_clear(BTN_TOUCH);
+ break;
- default: goto ignore;
- }
+ case 0x44: /* BarrelSwitch */
+ map_key_clear(BTN_STYLUS);
break;
- case HID_UP_LOGIVENDOR:
+ default: goto unknown;
+ }
+ break;
+
+ case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */
+ switch (usage->hid & HID_USAGE) {
+ case 0x000: goto ignore;
+ case 0x034: map_key_clear(KEY_SLEEP); break;
+ case 0x036: map_key_clear(BTN_MISC); break;
+
+ case 0x040: map_key_clear(KEY_MENU); break;
+ case 0x045: map_key_clear(KEY_RADIO); break;
+
+ case 0x083: map_key_clear(KEY_LAST); break;
+ case 0x088: map_key_clear(KEY_PC); break;
+ case 0x089: map_key_clear(KEY_TV); break;
+ case 0x08a: map_key_clear(KEY_WWW); break;
+ case 0x08b: map_key_clear(KEY_DVD); break;
+ case 0x08c: map_key_clear(KEY_PHONE); break;
+ case 0x08d: map_key_clear(KEY_PROGRAM); break;
+ case 0x08e: map_key_clear(KEY_VIDEOPHONE); break;
+ case 0x08f: map_key_clear(KEY_GAMES); break;
+ case 0x090: map_key_clear(KEY_MEMO); break;
+ case 0x091: map_key_clear(KEY_CD); break;
+ case 0x092: map_key_clear(KEY_VCR); break;
+ case 0x093: map_key_clear(KEY_TUNER); break;
+ case 0x094: map_key_clear(KEY_EXIT); break;
+ case 0x095: map_key_clear(KEY_HELP); break;
+ case 0x096: map_key_clear(KEY_TAPE); break;
+ case 0x097: map_key_clear(KEY_TV2); break;
+ case 0x098: map_key_clear(KEY_SAT); break;
+ case 0x09a: map_key_clear(KEY_PVR); break;
+
+ case 0x09c: map_key_clear(KEY_CHANNELUP); break;
+ case 0x09d: map_key_clear(KEY_CHANNELDOWN); break;
+ case 0x0a0: map_key_clear(KEY_VCR2); break;
+
+ case 0x0b0: map_key_clear(KEY_PLAY); break;
+ case 0x0b1: map_key_clear(KEY_PAUSE); break;
+ case 0x0b2: map_key_clear(KEY_RECORD); break;
+ case 0x0b3: map_key_clear(KEY_FASTFORWARD); break;
+ case 0x0b4: map_key_clear(KEY_REWIND); break;
+ case 0x0b5: map_key_clear(KEY_NEXTSONG); break;
+ case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break;
+ case 0x0b7: map_key_clear(KEY_STOPCD); break;
+ case 0x0b8: map_key_clear(KEY_EJECTCD); break;
+ case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break;
+
+ case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
+ case 0x0e0: map_abs_clear(ABS_VOLUME); break;
+ case 0x0e2: map_key_clear(KEY_MUTE); break;
+ case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
+ case 0x0e9: map_key_clear(KEY_VOLUMEUP); break;
+ case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
+
+ case 0x182: map_key_clear(KEY_BOOKMARKS); break;
+ case 0x183: map_key_clear(KEY_CONFIG); break;
+ case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
+ case 0x185: map_key_clear(KEY_EDITOR); break;
+ case 0x186: map_key_clear(KEY_SPREADSHEET); break;
+ case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break;
+ case 0x188: map_key_clear(KEY_PRESENTATION); break;
+ case 0x189: map_key_clear(KEY_DATABASE); break;
+ case 0x18a: map_key_clear(KEY_MAIL); break;
+ case 0x18b: map_key_clear(KEY_NEWS); break;
+ case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
+ case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
+ case 0x18e: map_key_clear(KEY_CALENDAR); break;
+ case 0x191: map_key_clear(KEY_FINANCE); break;
+ case 0x192: map_key_clear(KEY_CALC); break;
+ case 0x194: map_key_clear(KEY_FILE); break;
+ case 0x196: map_key_clear(KEY_WWW); break;
+ case 0x19c: map_key_clear(KEY_LOGOFF); break;
+ case 0x19e: map_key_clear(KEY_COFFEE); break;
+ case 0x1a6: map_key_clear(KEY_HELP); break;
+ case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
+ case 0x1b6: map_key_clear(KEY_MEDIA); break;
+ case 0x1b7: map_key_clear(KEY_SOUND); break;
+ case 0x1bc: map_key_clear(KEY_MESSENGER); break;
+ case 0x1bd: map_key_clear(KEY_INFO); break;
+ case 0x201: map_key_clear(KEY_NEW); break;
+ case 0x202: map_key_clear(KEY_OPEN); break;
+ case 0x203: map_key_clear(KEY_CLOSE); break;
+ case 0x204: map_key_clear(KEY_EXIT); break;
+ case 0x207: map_key_clear(KEY_SAVE); break;
+ case 0x208: map_key_clear(KEY_PRINT); break;
+ case 0x209: map_key_clear(KEY_PROPS); break;
+ case 0x21a: map_key_clear(KEY_UNDO); break;
+ case 0x21b: map_key_clear(KEY_COPY); break;
+ case 0x21c: map_key_clear(KEY_CUT); break;
+ case 0x21d: map_key_clear(KEY_PASTE); break;
+ case 0x21f: map_key_clear(KEY_FIND); break;
+ case 0x221: map_key_clear(KEY_SEARCH); break;
+ case 0x222: map_key_clear(KEY_GOTO); break;
+ case 0x223: map_key_clear(KEY_HOMEPAGE); break;
+ case 0x224: map_key_clear(KEY_BACK); break;
+ case 0x225: map_key_clear(KEY_FORWARD); break;
+ case 0x226: map_key_clear(KEY_STOP); break;
+ case 0x227: map_key_clear(KEY_REFRESH); break;
+ case 0x22a: map_key_clear(KEY_BOOKMARKS); break;
+ case 0x22d: map_key_clear(KEY_ZOOMIN); break;
+ case 0x22e: map_key_clear(KEY_ZOOMOUT); break;
+ case 0x22f: map_key_clear(KEY_ZOOMRESET); break;
+ case 0x233: map_key_clear(KEY_SCROLLUP); break;
+ case 0x234: map_key_clear(KEY_SCROLLDOWN); break;
+ case 0x238: map_rel(REL_HWHEEL); break;
+ case 0x25f: map_key_clear(KEY_CANCEL); break;
+ case 0x279: map_key_clear(KEY_REDO); break;
+
+ case 0x289: map_key_clear(KEY_REPLY); break;
+ case 0x28b: map_key_clear(KEY_FORWARDMAIL); break;
+ case 0x28c: map_key_clear(KEY_SEND); break;
+
+ default: goto ignore;
+ }
+ break;
+
+ case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
+ set_bit(EV_REP, input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ case 0x021: map_key_clear(KEY_PRINT); break;
+ case 0x070: map_key_clear(KEY_HP); break;
+ case 0x071: map_key_clear(KEY_CAMERA); break;
+ case 0x072: map_key_clear(KEY_SOUND); break;
+ case 0x073: map_key_clear(KEY_QUESTION); break;
+ case 0x080: map_key_clear(KEY_EMAIL); break;
+ case 0x081: map_key_clear(KEY_CHAT); break;
+ case 0x082: map_key_clear(KEY_SEARCH); break;
+ case 0x083: map_key_clear(KEY_CONNECT); break;
+ case 0x084: map_key_clear(KEY_FINANCE); break;
+ case 0x085: map_key_clear(KEY_SPORT); break;
+ case 0x086: map_key_clear(KEY_SHOP); break;
+ default: goto ignore;
+ }
+ break;
- goto ignore;
-
- case HID_UP_PID:
+ case HID_UP_MSVENDOR:
+ goto ignore;
- switch(usage->hid & HID_USAGE) {
- case 0xa4: map_key_clear(BTN_DEAD); break;
- default: goto ignore;
- }
- break;
+ case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */
+ set_bit(EV_REP, input->evbit);
+ goto ignore;
- default:
- unknown:
- if (field->report_size == 1) {
- if (field->report->type == HID_OUTPUT_REPORT) {
- map_led(LED_MISC);
- break;
- }
- map_key(BTN_MISC);
- break;
- }
- if (field->flags & HID_MAIN_ITEM_RELATIVE) {
- map_rel(REL_MISC);
+ case HID_UP_LOGIVENDOR:
+ goto ignore;
+
+ case HID_UP_PID:
+ switch (usage->hid & HID_USAGE) {
+ case 0xa4: map_key_clear(BTN_DEAD); break;
+ default: goto ignore;
+ }
+ break;
+
+ default:
+ unknown:
+ if (field->report_size == 1) {
+ if (field->report->type == HID_OUTPUT_REPORT) {
+ map_led(LED_MISC);
break;
}
- map_abs(ABS_MISC);
+ map_key(BTN_MISC);
+ break;
+ }
+ if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+ map_rel(REL_MISC);
break;
+ }
+ map_abs(ABS_MISC);
+ break;
}
mapped:
- if (device->quirks & HID_QUIRK_MIGHTYMOUSE) {
- if (usage->hid == HID_GD_Z)
- map_rel(REL_HWHEEL);
- else if (usage->code == BTN_1)
- map_key(BTN_2);
- else if (usage->code == BTN_2)
- map_key(BTN_1);
- }
-
- if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5 |
- HID_QUIRK_2WHEEL_MOUSE_HACK_B8)) && (usage->type == EV_REL) &&
- (usage->code == REL_WHEEL))
- set_bit(REL_HWHEEL, bit);
-
- if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
- || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007)))
+ if (device->driver->input_mapped && device->driver->input_mapped(device,
+ hidinput, field, usage, &bit, &max) < 0)
goto ignore;
- if ((device->quirks & HID_QUIRK_BAD_RELATIVE_KEYS) &&
- usage->type == EV_KEY && (field->flags & HID_MAIN_ITEM_RELATIVE))
- field->flags &= ~HID_MAIN_ITEM_RELATIVE;
-
set_bit(usage->type, input->evbit);
- if (device->quirks & HID_QUIRK_DUPLICATE_USAGES &&
- (usage->type == EV_KEY ||
- usage->type == EV_REL ||
- usage->type == EV_ABS))
- clear_bit(usage->code, bit);
-
while (usage->code <= max && test_and_set_bit(usage->code, bit))
usage->code = find_next_zero_bit(bit, max + 1, usage->code);
@@ -858,10 +585,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
if (!usage->type)
return;
- /* handle input events for quirky devices */
- if (hidinput_event_quirks(hid, field, usage, value))
- return;
-
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
int hat_dir = usage->hat_dir;
if (!hat_dir)
@@ -961,14 +684,14 @@ static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- return hid->hid_open(hid);
+ return hid->ll_driver->open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- hid->hid_close(hid);
+ hid->ll_driver->close(hid);
}
/*
@@ -977,7 +700,7 @@ static void hidinput_close(struct input_dev *dev)
* Read all reports and initialize the absolute field values.
*/
-int hidinput_connect(struct hid_device *hid)
+int hidinput_connect(struct hid_device *hid, unsigned int force)
{
struct hid_report *report;
struct hid_input *hidinput = NULL;
@@ -985,19 +708,20 @@ int hidinput_connect(struct hid_device *hid)
int i, j, k;
int max_report_type = HID_OUTPUT_REPORT;
- if (hid->quirks & HID_QUIRK_IGNORE_HIDINPUT)
- return -1;
-
INIT_LIST_HEAD(&hid->inputs);
- for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
- hid->collection[i].type == HID_COLLECTION_PHYSICAL)
- if (IS_INPUT_APPLICATION(hid->collection[i].usage))
- break;
+ if (!force) {
+ for (i = 0; i < hid->maxcollection; i++) {
+ struct hid_collection *col = &hid->collection[i];
+ if (col->type == HID_COLLECTION_APPLICATION ||
+ col->type == HID_COLLECTION_PHYSICAL)
+ if (IS_INPUT_APPLICATION(col->usage))
+ break;
+ }
- if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDINPUT) == 0)
- return -1;
+ if (i == hid->maxcollection)
+ return -1;
+ }
if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
max_report_type = HID_INPUT_REPORT;
@@ -1019,7 +743,8 @@ int hidinput_connect(struct hid_device *hid)
}
input_set_drvdata(input_dev, hid);
- input_dev->event = hid->hidinput_input_event;
+ input_dev->event =
+ hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
@@ -1032,7 +757,7 @@ int hidinput_connect(struct hid_device *hid)
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
- input_dev->dev.parent = hid->dev;
+ input_dev->dev.parent = hid->dev.parent;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
new file mode 100644
index 00000000000..406d8c82abf
--- /dev/null
+++ b/drivers/hid/hid-lg.c
@@ -0,0 +1,342 @@
+/*
+ * HID driver for some logitech "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+#include "hid-lg.h"
+
+#define LG_RDESC 0x001
+#define LG_BAD_RELATIVE_KEYS 0x002
+#define LG_DUPLICATE_USAGES 0x004
+#define LG_RESET_LEDS 0x008
+#define LG_EXPANDED_KEYMAP 0x010
+#define LG_IGNORE_DOUBLED_WHEEL 0x020
+#define LG_WIRELESS 0x040
+#define LG_INVERT_HWHEEL 0x080
+#define LG_NOGET 0x100
+#define LG_FF 0x200
+#define LG_FF2 0x400
+
+/*
+ * Certain Logitech keyboards send in report #3 keys which are far
+ * above the logical maximum described in descriptor. This extends
+ * the original value of 0x28c of logical maximum to 0x104d
+ */
+static void lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((quirks & LG_RDESC) && rsize >= 90 && rdesc[83] == 0x26 &&
+ rdesc[84] == 0x8c && rdesc[85] == 0x02) {
+ dev_info(&hdev->dev, "fixing up Logitech keyboard report "
+ "descriptor\n");
+ rdesc[84] = rdesc[89] = 0x4d;
+ rdesc[85] = rdesc[90] = 0x10;
+ }
+}
+
+#define lg_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+
+static int lg_ultrax_remote_mapping(struct hid_input *hi,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_LOGIVENDOR)
+ return 0;
+
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ /* Reported on Logitech Ultra X Media Remote */
+ case 0x004: lg_map_key_clear(KEY_AGAIN); break;
+ case 0x00d: lg_map_key_clear(KEY_HOME); break;
+ case 0x024: lg_map_key_clear(KEY_SHUFFLE); break;
+ case 0x025: lg_map_key_clear(KEY_TV); break;
+ case 0x026: lg_map_key_clear(KEY_MENU); break;
+ case 0x031: lg_map_key_clear(KEY_AUDIO); break;
+ case 0x032: lg_map_key_clear(KEY_TEXT); break;
+ case 0x033: lg_map_key_clear(KEY_LAST); break;
+ case 0x047: lg_map_key_clear(KEY_MP3); break;
+ case 0x048: lg_map_key_clear(KEY_DVD); break;
+ case 0x049: lg_map_key_clear(KEY_MEDIA); break;
+ case 0x04a: lg_map_key_clear(KEY_VIDEO); break;
+ case 0x04b: lg_map_key_clear(KEY_ANGLE); break;
+ case 0x04c: lg_map_key_clear(KEY_LANGUAGE); break;
+ case 0x04d: lg_map_key_clear(KEY_SUBTITLE); break;
+ case 0x051: lg_map_key_clear(KEY_RED); break;
+ case 0x052: lg_map_key_clear(KEY_CLOSE); break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int lg_wireless_mapping(struct hid_input *hi, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x1001: lg_map_key_clear(KEY_MESSENGER); break;
+ case 0x1003: lg_map_key_clear(KEY_SOUND); break;
+ case 0x1004: lg_map_key_clear(KEY_VIDEO); break;
+ case 0x1005: lg_map_key_clear(KEY_AUDIO); break;
+ case 0x100a: lg_map_key_clear(KEY_DOCUMENTS); break;
+ case 0x1011: lg_map_key_clear(KEY_PREVIOUSSONG); break;
+ case 0x1012: lg_map_key_clear(KEY_NEXTSONG); break;
+ case 0x1013: lg_map_key_clear(KEY_CAMERA); break;
+ case 0x1014: lg_map_key_clear(KEY_MESSENGER); break;
+ case 0x1015: lg_map_key_clear(KEY_RECORD); break;
+ case 0x1016: lg_map_key_clear(KEY_PLAYER); break;
+ case 0x1017: lg_map_key_clear(KEY_EJECTCD); break;
+ case 0x1018: lg_map_key_clear(KEY_MEDIA); break;
+ case 0x1019: lg_map_key_clear(KEY_PROG1); break;
+ case 0x101a: lg_map_key_clear(KEY_PROG2); break;
+ case 0x101b: lg_map_key_clear(KEY_PROG3); break;
+ case 0x101f: lg_map_key_clear(KEY_ZOOMIN); break;
+ case 0x1020: lg_map_key_clear(KEY_ZOOMOUT); break;
+ case 0x1021: lg_map_key_clear(KEY_ZOOMRESET); break;
+ case 0x1023: lg_map_key_clear(KEY_CLOSE); break;
+ case 0x1027: lg_map_key_clear(KEY_MENU); break;
+ /* this one is marked as 'Rotate' */
+ case 0x1028: lg_map_key_clear(KEY_ANGLE); break;
+ case 0x1029: lg_map_key_clear(KEY_SHUFFLE); break;
+ case 0x102a: lg_map_key_clear(KEY_BACK); break;
+ case 0x102b: lg_map_key_clear(KEY_CYCLEWINDOWS); break;
+ case 0x1041: lg_map_key_clear(KEY_BATTERY); break;
+ case 0x1042: lg_map_key_clear(KEY_WORDPROCESSOR); break;
+ case 0x1043: lg_map_key_clear(KEY_SPREADSHEET); break;
+ case 0x1044: lg_map_key_clear(KEY_PRESENTATION); break;
+ case 0x1045: lg_map_key_clear(KEY_UNDO); break;
+ case 0x1046: lg_map_key_clear(KEY_REDO); break;
+ case 0x1047: lg_map_key_clear(KEY_PRINT); break;
+ case 0x1048: lg_map_key_clear(KEY_SAVE); break;
+ case 0x1049: lg_map_key_clear(KEY_PROG1); break;
+ case 0x104a: lg_map_key_clear(KEY_PROG2); break;
+ case 0x104b: lg_map_key_clear(KEY_PROG3); break;
+ case 0x104c: lg_map_key_clear(KEY_PROG4); break;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int lg_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ /* extended mapping for certain Logitech hardware (Logitech cordless
+ desktop LX500) */
+ static const u8 e_keymap[] = {
+ 0,216, 0,213,175,156, 0, 0, 0, 0,
+ 144, 0, 0, 0, 0, 0, 0, 0, 0,212,
+ 174,167,152,161,112, 0, 0, 0,154, 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, 0, 0, 0, 0,183,184,185,186,187,
+ 188,189,190,191,192,193,194, 0, 0, 0
+ };
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+ unsigned int hid = usage->hid;
+
+ if (hdev->product == USB_DEVICE_ID_LOGITECH_RECEIVER &&
+ lg_ultrax_remote_mapping(hi, usage, bit, max))
+ return 1;
+
+ if ((quirks & LG_WIRELESS) && lg_wireless_mapping(hi, usage, bit, max))
+ return 1;
+
+ if ((hid & HID_USAGE_PAGE) != HID_UP_BUTTON)
+ return 0;
+
+ hid &= HID_USAGE;
+
+ /* Special handling for Logitech Cordless Desktop */
+ if (field->application == HID_GD_MOUSE) {
+ if ((quirks & LG_IGNORE_DOUBLED_WHEEL) &&
+ (hid == 7 || hid == 8))
+ return -1;
+ } else {
+ if ((quirks & LG_EXPANDED_KEYMAP) &&
+ hid < ARRAY_SIZE(e_keymap) &&
+ e_keymap[hid] != 0) {
+ hid_map_usage(hi, usage, bit, max, EV_KEY,
+ e_keymap[hid]);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int lg_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((quirks & LG_BAD_RELATIVE_KEYS) && usage->type == EV_KEY &&
+ (field->flags & HID_MAIN_ITEM_RELATIVE))
+ field->flags &= ~HID_MAIN_ITEM_RELATIVE;
+
+ if ((quirks & LG_DUPLICATE_USAGES) && (usage->type == EV_KEY ||
+ usage->type == EV_REL || usage->type == EV_ABS))
+ clear_bit(usage->code, *bit);
+
+ return 0;
+}
+
+static int lg_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((quirks & LG_INVERT_HWHEEL) && usage->code == REL_HWHEEL) {
+ input_event(field->hidinput->input, usage->type, usage->code,
+ -value);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ unsigned int connect_mask = HID_CONNECT_DEFAULT;
+ int ret;
+
+ hid_set_drvdata(hdev, (void *)quirks);
+
+ if (quirks & LG_NOGET)
+ hdev->quirks |= HID_QUIRK_NOGET;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ if (quirks & (LG_FF | LG_FF2))
+ connect_mask &= ~HID_CONNECT_FF;
+
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ if (quirks & LG_RESET_LEDS)
+ usbhid_set_leds(hdev);
+
+ if (quirks & LG_FF)
+ lgff_init(hdev);
+ if (quirks & LG_FF2)
+ lg2ff_init(hdev);
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id lg_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
+ .driver_data = LG_RDESC | LG_WIRELESS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
+ .driver_data = LG_RDESC | LG_WIRELESS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
+ .driver_data = LG_RDESC | LG_WIRELESS },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
+ .driver_data = LG_BAD_RELATIVE_KEYS },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP),
+ .driver_data = LG_DUPLICATE_USAGES },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE),
+ .driver_data = LG_DUPLICATE_USAGES },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI),
+ .driver_data = LG_DUPLICATE_USAGES },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD),
+ .driver_data = LG_RESET_LEDS },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD),
+ .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500),
+ .driver_data = LG_IGNORE_DOUBLED_WHEEL | LG_EXPANDED_KEYMAP },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3),
+ .driver_data = LG_INVERT_HWHEEL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150),
+ .driver_data = LG_INVERT_HWHEEL },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D),
+ .driver_data = LG_NOGET },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL),
+ .driver_data = LG_NOGET | LG_FF },
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2),
+ .driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2),
+ .driver_data = LG_FF2 },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, lg_devices);
+
+static struct hid_driver lg_driver = {
+ .name = "logitech",
+ .id_table = lg_devices,
+ .report_fixup = lg_report_fixup,
+ .input_mapping = lg_input_mapping,
+ .input_mapped = lg_input_mapped,
+ .event = lg_event,
+ .probe = lg_probe,
+};
+
+static int lg_init(void)
+{
+ return hid_register_driver(&lg_driver);
+}
+
+static void lg_exit(void)
+{
+ hid_unregister_driver(&lg_driver);
+}
+
+module_init(lg_init);
+module_exit(lg_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(logitech);
diff --git a/drivers/hid/hid-lg.h b/drivers/hid/hid-lg.h
new file mode 100644
index 00000000000..27ae750ca87
--- /dev/null
+++ b/drivers/hid/hid-lg.h
@@ -0,0 +1,18 @@
+#ifndef __HID_LG_H
+#define __HID_LG_H
+
+#include <linux/autoconf.h>
+
+#ifdef CONFIG_LOGITECH_FF
+int lgff_init(struct hid_device *hdev);
+#else
+static inline int lgff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#ifdef CONFIG_LOGIRUMBLEPAD2_FF
+int lg2ff_init(struct hid_device *hdev);
+#else
+static inline int lg2ff_init(struct hid_device *hdev) { return -1; }
+#endif
+
+#endif
diff --git a/drivers/hid/usbhid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index d469bd0061c..4e6dc6e2652 100644
--- a/drivers/hid/usbhid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -24,7 +24,9 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid.h"
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
struct lg2ff_device {
struct hid_report *report;
@@ -57,7 +59,7 @@ static int play_effect(struct input_dev *dev, void *data,
return 0;
}
-int hid_lg2ff_init(struct hid_device *hid)
+int lg2ff_init(struct hid_device *hid)
{
struct lg2ff_device *lg2ff;
struct hid_report *report;
@@ -69,18 +71,18 @@ int hid_lg2ff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- printk(KERN_ERR "hid-lg2ff: no output report found\n");
+ dev_err(&hid->dev, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 1) {
- printk(KERN_ERR "hid-lg2ff: output report is empty\n");
+ dev_err(&hid->dev, "output report is empty\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
- printk(KERN_ERR "hid-lg2ff: not enough values in the field\n");
+ dev_err(&hid->dev, "not enough values in the field\n");
return -ENODEV;
}
@@ -107,7 +109,7 @@ int hid_lg2ff_init(struct hid_device *hid)
usbhid_submit_report(hid, report, USB_DIR_OUT);
- printk(KERN_INFO "Force feedback for Logitech Rumblepad 2 by "
+ dev_info(&hid->dev, "Force feedback for Logitech Rumblepad 2 by "
"Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/usbhid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 4b7ab6a46d9..51aff08e10c 100644
--- a/drivers/hid/usbhid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -30,7 +30,9 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid.h"
+
+#include "usbhid/usbhid.h"
+#include "hid-lg.h"
struct dev_type {
u16 idVendor;
@@ -48,6 +50,12 @@ static const signed short ff_joystick[] = {
-1
};
+static const signed short ff_wheel[] = {
+ FF_CONSTANT,
+ FF_AUTOCENTER,
+ -1
+};
+
static const struct dev_type devices[] = {
{ 0x046d, 0xc211, ff_rumble },
{ 0x046d, 0xc219, ff_rumble },
@@ -55,7 +63,7 @@ static const struct dev_type devices[] = {
{ 0x046d, 0xc286, ff_joystick },
{ 0x046d, 0xc294, ff_joystick },
{ 0x046d, 0xc295, ff_joystick },
- { 0x046d, 0xca03, ff_joystick },
+ { 0x046d, 0xca03, ff_wheel },
};
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
@@ -100,7 +108,24 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
return 0;
}
-int hid_lgff_init(struct hid_device* hid)
+static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ __s32 *value = report->field[0]->value;
+ magnitude = (magnitude >> 12) & 0xf;
+ *value++ = 0xfe;
+ *value++ = 0x0d;
+ *value++ = magnitude; /* clockwise strength */
+ *value++ = magnitude; /* counter-clockwise strength */
+ *value++ = 0x80;
+ *value++ = 0x00;
+ *value = 0x00;
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+}
+
+int lgff_init(struct hid_device* hid)
{
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
@@ -145,6 +170,9 @@ int hid_lgff_init(struct hid_device* hid)
if (error)
return error;
+ if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
+ dev->ff->set_autocenter = hid_lgff_set_autocenter;
+
printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
return 0;
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
new file mode 100644
index 00000000000..d718b1607d0
--- /dev/null
+++ b/drivers/hid/hid-microsoft.c
@@ -0,0 +1,219 @@
+/*
+ * HID driver for some microsoft "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define MS_HIDINPUT 0x01
+#define MS_ERGONOMY 0x02
+#define MS_PRESENTER 0x04
+#define MS_RDESC 0x08
+#define MS_NOGET 0x10
+
+/*
+ * Microsoft Wireless Desktop Receiver (Model 1028) has several
+ * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
+ */
+static void ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((quirks & MS_RDESC) && rsize == 571 && rdesc[284] == 0x19 &&
+ rdesc[286] == 0x2a && rdesc[304] == 0x19 &&
+ rdesc[306] == 0x29 && rdesc[352] == 0x1a &&
+ rdesc[355] == 0x2a && rdesc[557] == 0x19 &&
+ rdesc[559] == 0x29) {
+ dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
+ "Model 1028 report descriptor\n");
+ rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
+ rdesc[352] = 0x36;
+ rdesc[286] = rdesc[355] = 0x46;
+ rdesc[306] = rdesc[559] = 0x45;
+ }
+}
+
+#define ms_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ms_ergonomy_kb_quirk(struct hid_input *hi, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct input_dev *input = hi->input;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0xfd06: ms_map_key_clear(KEY_CHAT); break;
+ case 0xfd07: ms_map_key_clear(KEY_PHONE); break;
+ case 0xff05:
+ set_bit(EV_REP, input->evbit);
+ ms_map_key_clear(KEY_F13);
+ set_bit(KEY_F14, input->keybit);
+ set_bit(KEY_F15, input->keybit);
+ set_bit(KEY_F16, input->keybit);
+ set_bit(KEY_F17, input->keybit);
+ set_bit(KEY_F18, input->keybit);
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int ms_presenter_8k_quirk(struct hid_input *hi, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ set_bit(EV_REP, hi->input->evbit);
+ switch (usage->hid & HID_USAGE) {
+ case 0xfd08: ms_map_key_clear(KEY_FORWARD); break;
+ case 0xfd09: ms_map_key_clear(KEY_BACK); break;
+ case 0xfd0b: ms_map_key_clear(KEY_PLAYPAUSE); break;
+ case 0xfd0e: ms_map_key_clear(KEY_CLOSE); break;
+ case 0xfd0f: ms_map_key_clear(KEY_PLAY); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_MSVENDOR)
+ return 0;
+
+ if (quirks & MS_ERGONOMY) {
+ int ret = ms_ergonomy_kb_quirk(hi, usage, bit, max);
+ if (ret)
+ return ret;
+ }
+
+ if ((quirks & MS_PRESENTER) &&
+ ms_presenter_8k_quirk(hi, usage, bit, max))
+ return 1;
+
+ return 0;
+}
+
+static int ms_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
+
+ if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput ||
+ !usage->type)
+ return 0;
+
+ /* Handling MS keyboards special buttons */
+ if (quirks & MS_ERGONOMY && usage->hid == (HID_UP_MSVENDOR | 0xff05)) {
+ struct input_dev *input = field->hidinput->input;
+ static unsigned int last_key = 0;
+ unsigned int key = 0;
+ switch (value) {
+ case 0x01: key = KEY_F14; break;
+ case 0x02: key = KEY_F15; break;
+ case 0x04: key = KEY_F16; break;
+ case 0x08: key = KEY_F17; break;
+ case 0x10: key = KEY_F18; break;
+ }
+ if (key) {
+ input_event(input, usage->type, key, 1);
+ last_key = key;
+ } else
+ input_event(input, usage->type, last_key, 0);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ int ret;
+
+ hid_set_drvdata(hdev, (void *)quirks);
+
+ if (quirks & MS_NOGET)
+ hdev->quirks |= HID_QUIRK_NOGET;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
+ HID_CONNECT_HIDINPUT_FORCE : 0));
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id ms_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV),
+ .driver_data = MS_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
+ .driver_data = MS_ERGONOMY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
+ .driver_data = MS_ERGONOMY | MS_RDESC },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
+ .driver_data = MS_PRESENTER },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0),
+ .driver_data = MS_NOGET },
+
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
+ .driver_data = MS_PRESENTER },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ms_devices);
+
+static struct hid_driver ms_driver = {
+ .name = "microsoft",
+ .id_table = ms_devices,
+ .report_fixup = ms_report_fixup,
+ .input_mapping = ms_input_mapping,
+ .event = ms_event,
+ .probe = ms_probe,
+};
+
+static int ms_init(void)
+{
+ return hid_register_driver(&ms_driver);
+}
+
+static void ms_exit(void)
+{
+ hid_unregister_driver(&ms_driver);
+}
+
+module_init(ms_init);
+module_exit(ms_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(microsoft);
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
new file mode 100644
index 00000000000..f3a85a065f1
--- /dev/null
+++ b/drivers/hid/hid-monterey.c
@@ -0,0 +1,82 @@
+/*
+ * HID driver for some monterey "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
+ dev_info(&hdev->dev, "fixing up button/consumer in HID report "
+ "descriptor\n");
+ rdesc[30] = 0x0c;
+ }
+}
+
+#define mr_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int mr_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x156: mr_map_key_clear(KEY_WORDPROCESSOR); break;
+ case 0x157: mr_map_key_clear(KEY_SPREADSHEET); break;
+ case 0x158: mr_map_key_clear(KEY_PRESENTATION); break;
+ case 0x15c: mr_map_key_clear(KEY_STOP); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static const struct hid_device_id mr_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mr_devices);
+
+static struct hid_driver mr_driver = {
+ .name = "monterey",
+ .id_table = mr_devices,
+ .report_fixup = mr_report_fixup,
+ .input_mapping = mr_input_mapping,
+};
+
+static int mr_init(void)
+{
+ return hid_register_driver(&mr_driver);
+}
+
+static void mr_exit(void)
+{
+ hid_unregister_driver(&mr_driver);
+}
+
+module_init(mr_init);
+module_exit(mr_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(monterey);
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
new file mode 100644
index 00000000000..10945fe12d5
--- /dev/null
+++ b/drivers/hid/hid-petalynx.c
@@ -0,0 +1,122 @@
+/*
+ * HID driver for some petalynx "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/* Petalynx Maxter Remote has maximum for consumer page set too low */
+static void pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
+ rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
+ rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
+ dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
+ "descriptor\n");
+ rdesc[60] = 0xfa;
+ rdesc[40] = 0xfa;
+ }
+}
+
+#define pl_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int pl_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_LOGIVENDOR) {
+ switch (usage->hid & HID_USAGE) {
+ case 0x05a: pl_map_key_clear(KEY_TEXT); break;
+ case 0x05b: pl_map_key_clear(KEY_RED); break;
+ case 0x05c: pl_map_key_clear(KEY_GREEN); break;
+ case 0x05d: pl_map_key_clear(KEY_YELLOW); break;
+ case 0x05e: pl_map_key_clear(KEY_BLUE); break;
+ default:
+ return 0;
+ }
+ return 1;
+ }
+
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+ switch (usage->hid & HID_USAGE) {
+ case 0x0f6: pl_map_key_clear(KEY_NEXT); break;
+ case 0x0fa: pl_map_key_clear(KEY_BACK); break;
+ default:
+ return 0;
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ hdev->quirks |= HID_QUIRK_NOGET;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+ .name = "petalynx",
+ .id_table = pl_devices,
+ .report_fixup = pl_report_fixup,
+ .input_mapping = pl_input_mapping,
+ .probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+ return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+ hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(petalynx);
diff --git a/drivers/hid/usbhid/hid-plff.c b/drivers/hid/hid-pl.c
index 9eb83cf9d22..acd81558618 100644
--- a/drivers/hid/usbhid/hid-plff.c
+++ b/drivers/hid/hid-pl.c
@@ -9,7 +9,7 @@
* - contains two reports, one for each port (HID_QUIRK_MULTI_INPUT)
*
* 0e8f:0003 "GreenAsia Inc. USB Joystick "
- * - tested with Köng Gaming gamepad
+ * - tested with K??ng Gaming gamepad
*
* Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
*/
@@ -38,7 +38,11 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
-#include "usbhid.h"
+
+#include "hid-ids.h"
+
+#ifdef CONFIG_PANTHERLORD_FF
+#include "usbhid/usbhid.h"
struct plff_device {
struct hid_report *report;
@@ -66,7 +70,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
return 0;
}
-int hid_plff_init(struct hid_device *hid)
+static int plff_init(struct hid_device *hid)
{
struct plff_device *plff;
struct hid_report *report;
@@ -86,7 +90,7 @@ int hid_plff_init(struct hid_device *hid)
currently unknown. */
if (list_empty(report_list)) {
- printk(KERN_ERR "hid-plff: no output reports found\n");
+ dev_err(&hid->dev, "no output reports found\n");
return -ENODEV;
}
@@ -95,18 +99,19 @@ int hid_plff_init(struct hid_device *hid)
report_ptr = report_ptr->next;
if (report_ptr == report_list) {
- printk(KERN_ERR "hid-plff: required output report is missing\n");
+ dev_err(&hid->dev, "required output report is "
+ "missing\n");
return -ENODEV;
}
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- printk(KERN_ERR "hid-plff: no fields in the report\n");
+ dev_err(&hid->dev, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 4) {
- printk(KERN_ERR "hid-plff: not enough values in the field\n");
+ dev_err(&hid->dev, "not enough values in the field\n");
return -ENODEV;
}
@@ -132,8 +137,70 @@ int hid_plff_init(struct hid_device *hid)
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
}
- printk(KERN_INFO "hid-plff: Force feedback for PantherLord/GreenAsia "
+ dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
"devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
+#else
+static inline int plff_init(struct hid_device *hid)
+{
+ return 0;
+}
+#endif
+
+static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ if (id->driver_data)
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err;
+ }
+
+ plff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id pl_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR),
+ .driver_data = 1 }, /* Twin USB Joystick */
+ { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003), }, /* GreenAsia Inc. USB Joystick */
+ { }
+};
+MODULE_DEVICE_TABLE(hid, pl_devices);
+
+static struct hid_driver pl_driver = {
+ .name = "pantherlord",
+ .id_table = pl_devices,
+ .probe = pl_probe,
+};
+
+static int pl_init(void)
+{
+ return hid_register_driver(&pl_driver);
+}
+
+static void pl_exit(void)
+{
+ hid_unregister_driver(&pl_driver);
+}
+
+module_init(pl_init);
+module_exit(pl_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(pantherlord);
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
new file mode 100644
index 00000000000..15f3c049245
--- /dev/null
+++ b/drivers/hid/hid-samsung.c
@@ -0,0 +1,100 @@
+/*
+ * HID driver for some samsung "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+/*
+ * Samsung IrDA remote controller (reports as Cypress USB Mouse).
+ *
+ * Vendor specific report #4 has a size of 48 bit,
+ * and therefore is not accepted when inspecting the descriptors.
+ * As a workaround we reinterpret the report as:
+ * Variable type, count 6, size 8 bit, log. maximum 255
+ * The burden to reconstruct the data is moved into user space.
+ */
+static void samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 182 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
+ rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
+ rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
+ rdesc[182] == 0x40) {
+ dev_info(&hdev->dev, "fixing up Samsung IrDA report "
+ "descriptor\n");
+ rdesc[176] = 0xff;
+ rdesc[178] = 0x08;
+ rdesc[180] = 0x06;
+ rdesc[182] = 0x42;
+ }
+}
+
+static int samsung_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, (HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT) |
+ HID_CONNECT_HIDDEV_FORCE);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ return 0;
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id samsung_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, samsung_devices);
+
+static struct hid_driver samsung_driver = {
+ .name = "samsung",
+ .id_table = samsung_devices,
+ .report_fixup = samsung_report_fixup,
+ .probe = samsung_probe,
+};
+
+static int samsung_init(void)
+{
+ return hid_register_driver(&samsung_driver);
+}
+
+static void samsung_exit(void)
+{
+ hid_unregister_driver(&samsung_driver);
+}
+
+module_init(samsung_init);
+module_exit(samsung_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(samsung);
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
new file mode 100644
index 00000000000..3af8095a7de
--- /dev/null
+++ b/drivers/hid/hid-sony.c
@@ -0,0 +1,110 @@
+/*
+ * HID driver for some sony "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational". Without this, the ps3 controller will not report any
+ * events.
+ */
+static int sony_set_operational(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *dev = interface_to_usbdev(intf);
+ __u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
+ int ret;
+ char *buf = kmalloc(18, GFP_KERNEL);
+
+ if (!buf)
+ return -ENOMEM;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE,
+ (3 << 8) | 0xf2, ifnum, buf, 17,
+ USB_CTRL_GET_TIMEOUT);
+ if (ret < 0)
+ dev_err(&hdev->dev, "can't set operational mode\n");
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err_free;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
+ HID_CONNECT_HIDDEV_FORCE);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err_free;
+ }
+
+ ret = sony_set_operational(hdev);
+ if (ret)
+ goto err_stop;
+
+ return 0;
+err_stop:
+ hid_hw_stop(hdev);
+err_free:
+ return ret;
+}
+
+static const struct hid_device_id sony_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, sony_devices);
+
+static struct hid_driver sony_driver = {
+ .name = "sony",
+ .id_table = sony_devices,
+ .probe = sony_probe,
+};
+
+static int sony_init(void)
+{
+ return hid_register_driver(&sony_driver);
+}
+
+static void sony_exit(void)
+{
+ hid_unregister_driver(&sony_driver);
+}
+
+module_init(sony_init);
+module_exit(sony_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sony);
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
new file mode 100644
index 00000000000..5ba68f7dbb7
--- /dev/null
+++ b/drivers/hid/hid-sunplus.c
@@ -0,0 +1,82 @@
+/*
+ * HID driver for some sunplus "special" devices
+ *
+ * Copyright (c) 1999 Andreas Gal
+ * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
+ * Copyright (c) 2006-2007 Jiri Kosina
+ * Copyright (c) 2007 Paul Walmsley
+ * Copyright (c) 2008 Jiri Slaby
+ */
+
+/*
+ * 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/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static void sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int rsize)
+{
+ if (rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
+ rdesc[106] == 0x03) {
+ dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
+ "report descriptor\n");
+ rdesc[105] = rdesc[110] = 0x03;
+ rdesc[106] = rdesc[111] = 0x21;
+ }
+}
+
+#define sp_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int sp_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x2003: sp_map_key_clear(KEY_ZOOMIN); break;
+ case 0x2103: sp_map_key_clear(KEY_ZOOMOUT); break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static const struct hid_device_id sp_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, sp_devices);
+
+static struct hid_driver sp_driver = {
+ .name = "sunplus",
+ .id_table = sp_devices,
+ .report_fixup = sp_report_fixup,
+ .input_mapping = sp_input_mapping,
+};
+
+static int sp_init(void)
+{
+ return hid_register_driver(&sp_driver);
+}
+
+static void sp_exit(void)
+{
+ hid_unregister_driver(&sp_driver);
+}
+
+module_init(sp_init);
+module_exit(sp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(sunplus);
diff --git a/drivers/hid/usbhid/hid-tmff.c b/drivers/hid/hid-tmff.c
index 144578b1a00..1b7cba0f7e1 100644
--- a/drivers/hid/usbhid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -27,23 +27,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/hid.h>
#include <linux/input.h>
-
-#undef DEBUG
#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
-struct dev_type {
- u16 idVendor;
- u16 idProduct;
- const signed short *ff;
-};
-
static const signed short ff_rumble[] = {
FF_RUMBLE,
-1
@@ -54,21 +48,13 @@ static const signed short ff_joystick[] = {
-1
};
-static const struct dev_type devices[] = {
- { 0x44f, 0xb300, ff_rumble },
- { 0x44f, 0xb304, ff_rumble },
- { 0x44f, 0xb651, ff_rumble }, /* FGT Rumble Force Wheel */
- { 0x44f, 0xb654, ff_joystick }, /* FGT Force Feedback Wheel */
-};
-
struct tmff_device {
struct hid_report *report;
struct hid_field *ff_field;
};
/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale_u16(unsigned int in,
- int minimum, int maximum)
+static inline int tmff_scale_u16(unsigned int in, int minimum, int maximum)
{
int ret;
@@ -81,8 +67,7 @@ static inline int hid_tmff_scale_u16(unsigned int in,
}
/* Changes values from -0x80 to 0x7f into values from minimum to maximum */
-static inline int hid_tmff_scale_s8(int in,
- int minimum, int maximum)
+static inline int tmff_scale_s8(int in, int minimum, int maximum)
{
int ret;
@@ -94,7 +79,8 @@ static inline int hid_tmff_scale_s8(int in,
return ret;
}
-static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+static int tmff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
@@ -104,10 +90,10 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
switch (effect->type) {
case FF_CONSTANT:
- x = hid_tmff_scale_s8(effect->u.ramp.start_level,
+ x = tmff_scale_s8(effect->u.ramp.start_level,
ff_field->logical_minimum,
ff_field->logical_maximum);
- y = hid_tmff_scale_s8(effect->u.ramp.end_level,
+ y = tmff_scale_s8(effect->u.ramp.end_level,
ff_field->logical_minimum,
ff_field->logical_maximum);
@@ -118,10 +104,10 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
break;
case FF_RUMBLE:
- left = hid_tmff_scale_u16(effect->u.rumble.weak_magnitude,
+ left = tmff_scale_u16(effect->u.rumble.weak_magnitude,
ff_field->logical_minimum,
ff_field->logical_maximum);
- right = hid_tmff_scale_u16(effect->u.rumble.strong_magnitude,
+ right = tmff_scale_u16(effect->u.rumble.strong_magnitude,
ff_field->logical_minimum,
ff_field->logical_maximum);
@@ -134,14 +120,14 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef
return 0;
}
-int hid_tmff_init(struct hid_device *hid)
+static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
{
struct tmff_device *tmff;
struct hid_report *report;
struct list_head *report_list;
- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
- const signed short *ff_bits = ff_joystick;
int error;
int i;
@@ -163,63 +149,121 @@ int hid_tmff_init(struct hid_device *hid)
switch (field->usage[0].hid) {
case THRUSTMASTER_USAGE_FF:
if (field->report_count < 2) {
- warn("ignoring FF field with report_count < 2");
+ dev_warn(&hid->dev, "ignoring FF field "
+ "with report_count < 2\n");
continue;
}
- if (field->logical_maximum == field->logical_minimum) {
- warn("ignoring FF field with logical_maximum == logical_minimum");
+ if (field->logical_maximum ==
+ field->logical_minimum) {
+ dev_warn(&hid->dev, "ignoring FF field "
+ "with logical_maximum "
+ "== logical_minimum\n");
continue;
}
if (tmff->report && tmff->report != report) {
- warn("ignoring FF field in other report");
+ dev_warn(&hid->dev, "ignoring FF field "
+ "in other report\n");
continue;
}
if (tmff->ff_field && tmff->ff_field != field) {
- warn("ignoring duplicate FF field");
+ dev_warn(&hid->dev, "ignoring "
+ "duplicate FF field\n");
continue;
}
tmff->report = report;
tmff->ff_field = field;
- for (i = 0; i < ARRAY_SIZE(devices); i++) {
- if (input_dev->id.vendor == devices[i].idVendor &&
- input_dev->id.product == devices[i].idProduct) {
- ff_bits = devices[i].ff;
- break;
- }
- }
-
for (i = 0; ff_bits[i] >= 0; i++)
set_bit(ff_bits[i], input_dev->ffbit);
break;
default:
- warn("ignoring unknown output usage %08x", field->usage[0].hid);
+ dev_warn(&hid->dev, "ignoring unknown output "
+ "usage %08x\n",
+ field->usage[0].hid);
continue;
}
}
}
if (!tmff->report) {
- err("cant find FF field in output reports\n");
+ dev_err(&hid->dev, "can't find FF field in output reports\n");
error = -ENODEV;
goto fail;
}
- error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+ error = input_ff_create_memless(input_dev, tmff, tmff_play);
if (error)
goto fail;
- info("Force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>");
+ dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
+ "Verituse <zinx@epicsol.org>");
return 0;
- fail:
+fail:
kfree(tmff);
return error;
}
+static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err;
+ }
+
+ tmff_init(hdev, (void *)id->driver_data);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id tm_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300),
+ .driver_data = (unsigned long)ff_rumble },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304),
+ .driver_data = (unsigned long)ff_rumble },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */
+ .driver_data = (unsigned long)ff_rumble },
+ { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654), /* FGT Force Feedback Wheel */
+ .driver_data = (unsigned long)ff_joystick },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, tm_devices);
+
+static struct hid_driver tm_driver = {
+ .name = "thrustmaster",
+ .id_table = tm_devices,
+ .probe = tm_probe,
+};
+
+static int tm_init(void)
+{
+ return hid_register_driver(&tm_driver);
+}
+
+static void tm_exit(void)
+{
+ hid_unregister_driver(&tm_driver);
+}
+
+module_init(tm_init);
+module_exit(tm_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(thrustmaster);
diff --git a/drivers/hid/usbhid/hid-zpff.c b/drivers/hid/hid-zpff.c
index 5a688274f6a..ea82f3718b2 100644
--- a/drivers/hid/usbhid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -21,16 +21,19 @@
*/
+#include <linux/hid.h>
#include <linux/input.h>
#include <linux/usb.h>
-#include <linux/hid.h>
-#include "usbhid.h"
+
+#include "hid-ids.h"
+
+#include "usbhid/usbhid.h"
struct zpff_device {
struct hid_report *report;
};
-static int hid_zpff_play(struct input_dev *dev, void *data,
+static int zpff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct hid_device *hid = input_get_drvdata(dev);
@@ -58,7 +61,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data,
return 0;
}
-int hid_zpff_init(struct hid_device *hid)
+static int zpff_init(struct hid_device *hid)
{
struct zpff_device *zpff;
struct hid_report *report;
@@ -70,14 +73,14 @@ int hid_zpff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- printk(KERN_ERR "hid-zpff: no output report found\n");
+ dev_err(&hid->dev, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 4) {
- printk(KERN_ERR "hid-zpff: not enough fields in report\n");
+ dev_err(&hid->dev, "not enough fields in report\n");
return -ENODEV;
}
@@ -87,7 +90,7 @@ int hid_zpff_init(struct hid_device *hid)
set_bit(FF_RUMBLE, dev->ffbit);
- error = input_ff_create_memless(dev, zpff, hid_zpff_play);
+ error = input_ff_create_memless(dev, zpff, zpff_play);
if (error) {
kfree(zpff);
return error;
@@ -100,8 +103,60 @@ int hid_zpff_init(struct hid_device *hid)
zpff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
- printk(KERN_INFO "Force feedback for Zeroplus based devices by "
+ dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
"Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
+
+static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ dev_err(&hdev->dev, "hw start failed\n");
+ goto err;
+ }
+
+ zpff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id zp_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, zp_devices);
+
+static struct hid_driver zp_driver = {
+ .name = "zeroplus",
+ .id_table = zp_devices,
+ .probe = zp_probe,
+};
+
+static int zp_init(void)
+{
+ return hid_register_driver(&zp_driver);
+}
+
+static void zp_exit(void)
+{
+ hid_unregister_driver(&zp_driver);
+}
+
+module_init(zp_init);
+module_exit(zp_exit);
+MODULE_LICENSE("GPL");
+
+HID_COMPAT_LOAD_DRIVER(zeroplus);
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index c40f0403eda..497e0d1dd3c 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -113,7 +113,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
if (!dev->hid_output_raw_report)
return -ENODEV;
- if (count > HID_MIN_BUFFER_SIZE) {
+ if (count > HID_MAX_BUFFER_SIZE) {
printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
task_pid_nr(current));
return -EINVAL;
@@ -181,7 +181,7 @@ static int hidraw_open(struct inode *inode, struct file *file)
dev = hidraw_table[minor];
if (!dev->open++)
- dev->hid->hid_open(dev->hid);
+ dev->hid->ll_driver->open(dev->hid);
out_unlock:
spin_unlock(&minors_lock);
@@ -207,7 +207,7 @@ static int hidraw_release(struct inode * inode, struct file * file)
dev = hidraw_table[minor];
if (!dev->open--) {
if (list->hidraw->exist)
- dev->hid->hid_close(dev->hid);
+ dev->hid->ll_driver->close(dev->hid);
else
kfree(list->hidraw);
}
@@ -367,7 +367,7 @@ void hidraw_disconnect(struct hid_device *hid)
device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
if (hidraw->open) {
- hid->hid_close(hid);
+ hid->ll_driver->close(hid);
wake_up_interruptible(&hidraw->wait);
} else {
kfree(hidraw);
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 18f09104765..5d9aa95fc3e 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -24,88 +24,13 @@ config USB_HID
comment "Input core support is needed for USB HID input layer or HIDBP support"
depends on USB_HID && INPUT=n
-config USB_HIDINPUT_POWERBOOK
- bool "Enable support for Apple laptop/aluminum USB special keys"
- default n
- depends on USB_HID
- help
- Say Y here if you want support for the special keys (Fn, Numlock) on
- Apple iBooks, PowerBooks, MacBooks, MacBook Pros and aluminum USB
- keyboards.
-
- If unsure, say N.
-
-config HID_FF
- bool "Force feedback support (EXPERIMENTAL)"
- depends on USB_HID && EXPERIMENTAL
- help
- Say Y here is you want force feedback support for a few HID devices.
- See below for a list of supported devices.
-
- See <file:Documentation/input/ff.txt> for a description of the force
- feedback API.
-
- If unsure, say N.
-
config HID_PID
bool "PID device support"
- depends on HID_FF
help
Say Y here if you have a PID-compliant device and wish to enable force
feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
devices.
-config LOGITECH_FF
- bool "Logitech devices support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have one of these devices:
- - Logitech WingMan Cordless RumblePad
- - Logitech WingMan Cordless RumblePad 2
- - Logitech WingMan Force 3D
- - Logitech Formula Force EX
- - Logitech MOMO Force wheel
-
- and if you want to enable force feedback for them.
- Note: if you say N here, this device will still be supported, but without
- force feedback.
-
-config LOGIRUMBLEPAD2_FF
- bool "Logitech Rumblepad 2 support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you want to enable force feedback support for Logitech
- Rumblepad 2 devices.
-
-config PANTHERLORD_FF
- bool "PantherLord/GreenAsia based device support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a PantherLord/GreenAsia based game controller
- or adapter and want to enable force feedback support for it.
-
-config THRUSTMASTER_FF
- bool "ThrustMaster devices support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
- a THRUSTMASTER Ferrari GT Rumble Force or Force Feedback Wheel,
- and want to enable force feedback support for it.
- Note: if you say N here, this device will still be supported, but without
- force feedback.
-
-config ZEROPLUS_FF
- bool "Zeroplus based game controller support"
- depends on HID_FF
- select INPUT_FF_MEMLESS if USB_HID
- help
- Say Y here if you have a Zeroplus based game controller and want to
- enable force feedback for it.
-
config USB_HIDDEV
bool "/dev/hiddev raw HID device support"
depends on USB_HID
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 00a7b709019..1329ecb37a1 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -13,24 +13,6 @@ endif
ifeq ($(CONFIG_HID_PID),y)
usbhid-objs += hid-pidff.o
endif
-ifeq ($(CONFIG_LOGITECH_FF),y)
- usbhid-objs += hid-lgff.o
-endif
-ifeq ($(CONFIG_LOGIRUMBLEPAD2_FF),y)
- usbhid-objs += hid-lg2ff.o
-endif
-ifeq ($(CONFIG_PANTHERLORD_FF),y)
- usbhid-objs += hid-plff.o
-endif
-ifeq ($(CONFIG_THRUSTMASTER_FF),y)
- usbhid-objs += hid-tmff.o
-endif
-ifeq ($(CONFIG_ZEROPLUS_FF),y)
- usbhid-objs += hid-zpff.o
-endif
-ifeq ($(CONFIG_HID_FF),y)
- usbhid-objs += hid-ff.o
-endif
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 27fe4d8912c..1d3b8a394d4 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -44,8 +44,6 @@
#define DRIVER_DESC "USB HID core driver"
#define DRIVER_LICENSE "GPL"
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
- "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
/*
* Module parameters.
*/
@@ -61,12 +59,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
" quirks=vendorID:productID:quirks"
" where vendorID, productID, and quirks are all in"
" 0x-prefixed hex");
-static char *rdesc_quirks_param[MAX_USBHID_BOOT_QUIRKS] = { [ 0 ... (MAX_USBHID_BOOT_QUIRKS - 1) ] = NULL };
-module_param_array_named(rdesc_quirks, rdesc_quirks_param, charp, NULL, 0444);
-MODULE_PARM_DESC(rdesc_quirks, "Add/modify report descriptor quirks by specifying "
- " rdesc_quirks=vendorID:productID:rdesc_quirks"
- " where vendorID, productID, and rdesc_quirks are all in"
- " 0x-prefixed hex");
/*
* Input submission and I/O error handler.
*/
@@ -197,31 +189,32 @@ static void hid_irq_in(struct urb *urb)
int status;
switch (urb->status) {
- case 0: /* success */
- usbhid->retry_delay = 0;
- hid_input_report(urb->context, HID_INPUT_REPORT,
- urb->transfer_buffer,
- urb->actual_length, 1);
- break;
- case -EPIPE: /* stall */
- clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- set_bit(HID_CLEAR_HALT, &usbhid->iofl);
- schedule_work(&usbhid->reset_work);
- return;
- case -ECONNRESET: /* unlink */
- case -ENOENT:
- case -ESHUTDOWN: /* unplug */
- clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- return;
- case -EILSEQ: /* protocol error or unplug */
- case -EPROTO: /* protocol error or unplug */
- case -ETIME: /* protocol error or unplug */
- case -ETIMEDOUT: /* Should never happen, but... */
- clear_bit(HID_IN_RUNNING, &usbhid->iofl);
- hid_io_error(hid);
- return;
- default: /* error */
- warn("input irq status %d received", urb->status);
+ case 0: /* success */
+ usbhid->retry_delay = 0;
+ hid_input_report(urb->context, HID_INPUT_REPORT,
+ urb->transfer_buffer,
+ urb->actual_length, 1);
+ break;
+ case -EPIPE: /* stall */
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ set_bit(HID_CLEAR_HALT, &usbhid->iofl);
+ schedule_work(&usbhid->reset_work);
+ return;
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+ case -ESHUTDOWN: /* unplug */
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ return;
+ case -EILSEQ: /* protocol error or unplug */
+ case -EPROTO: /* protocol error or unplug */
+ case -ETIME: /* protocol error or unplug */
+ case -ETIMEDOUT: /* Should never happen, but... */
+ clear_bit(HID_IN_RUNNING, &usbhid->iofl);
+ hid_io_error(hid);
+ return;
+ default: /* error */
+ dev_warn(&urb->dev->dev, "input irq status %d "
+ "received\n", urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC);
@@ -240,13 +233,16 @@ static void hid_irq_in(struct urb *urb)
static int hid_submit_out(struct hid_device *hid)
{
struct hid_report *report;
+ char *raw_report;
struct usbhid_device *usbhid = hid->driver_data;
- report = usbhid->out[usbhid->outtail];
+ report = usbhid->out[usbhid->outtail].report;
+ raw_report = usbhid->out[usbhid->outtail].raw_report;
- hid_output_report(report, usbhid->outbuf);
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
+ memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length);
+ kfree(raw_report);
dbg_hid("submitting out urb\n");
@@ -262,17 +258,20 @@ static int hid_submit_ctrl(struct hid_device *hid)
{
struct hid_report *report;
unsigned char dir;
+ char *raw_report;
int len;
struct usbhid_device *usbhid = hid->driver_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
+ raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
dir = usbhid->ctrl[usbhid->ctrltail].dir;
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
- hid_output_report(report, usbhid->ctrlbuf);
usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0);
usbhid->urbctrl->transfer_buffer_length = len;
+ memcpy(usbhid->ctrlbuf, raw_report, len);
+ kfree(raw_report);
} else {
int maxpacket, padlen;
@@ -319,17 +318,18 @@ static void hid_irq_out(struct urb *urb)
int unplug = 0;
switch (urb->status) {
- case 0: /* success */
- break;
- case -ESHUTDOWN: /* unplug */
- unplug = 1;
- case -EILSEQ: /* protocol error or unplug */
- case -EPROTO: /* protocol error or unplug */
- case -ECONNRESET: /* unlink */
- case -ENOENT:
- break;
- default: /* error */
- warn("output irq status %d received", urb->status);
+ case 0: /* success */
+ break;
+ case -ESHUTDOWN: /* unplug */
+ unplug = 1;
+ case -EILSEQ: /* protocol error or unplug */
+ case -EPROTO: /* protocol error or unplug */
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+ break;
+ default: /* error */
+ dev_warn(&urb->dev->dev, "output irq status %d "
+ "received\n", urb->status);
}
spin_lock_irqsave(&usbhid->outlock, flags);
@@ -367,21 +367,23 @@ static void hid_ctrl(struct urb *urb)
spin_lock_irqsave(&usbhid->ctrllock, flags);
switch (urb->status) {
- case 0: /* success */
- if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
- hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type,
- urb->transfer_buffer, urb->actual_length, 0);
- break;
- case -ESHUTDOWN: /* unplug */
- unplug = 1;
- case -EILSEQ: /* protocol error or unplug */
- case -EPROTO: /* protocol error or unplug */
- case -ECONNRESET: /* unlink */
- case -ENOENT:
- case -EPIPE: /* report not available */
- break;
- default: /* error */
- warn("ctrl urb status %d received", urb->status);
+ case 0: /* success */
+ if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN)
+ hid_input_report(urb->context,
+ usbhid->ctrl[usbhid->ctrltail].report->type,
+ urb->transfer_buffer, urb->actual_length, 0);
+ break;
+ case -ESHUTDOWN: /* unplug */
+ unplug = 1;
+ case -EILSEQ: /* protocol error or unplug */
+ case -EPROTO: /* protocol error or unplug */
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+ case -EPIPE: /* report not available */
+ break;
+ default: /* error */
+ dev_warn(&urb->dev->dev, "ctrl urb status %d "
+ "received\n", urb->status);
}
if (unplug)
@@ -408,6 +410,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
int head;
unsigned long flags;
struct usbhid_device *usbhid = hid->driver_data;
+ int len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN)
return;
@@ -418,11 +421,18 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
spin_unlock_irqrestore(&usbhid->outlock, flags);
- warn("output queue full");
+ dev_warn(&hid->dev, "output queue full\n");
return;
}
- usbhid->out[usbhid->outhead] = report;
+ usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
+ if (!usbhid->out[usbhid->outhead].raw_report) {
+ spin_unlock_irqrestore(&usbhid->outlock, flags);
+ warn("output queueing failed");
+ return;
+ }
+ hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
+ usbhid->out[usbhid->outhead].report = report;
usbhid->outhead = head;
if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl))
@@ -437,10 +447,19 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
- warn("control queue full");
+ dev_warn(&hid->dev, "control queue full\n");
return;
}
+ if (dir == USB_DIR_OUT) {
+ usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
+ if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
+ spin_unlock_irqrestore(&usbhid->ctrllock, flags);
+ warn("control queueing failed");
+ return;
+ }
+ hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
+ }
usbhid->ctrl[usbhid->ctrlhead].report = report;
usbhid->ctrl[usbhid->ctrlhead].dir = dir;
usbhid->ctrlhead = head;
@@ -451,6 +470,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
spin_unlock_irqrestore(&usbhid->ctrllock, flags);
}
+EXPORT_SYMBOL_GPL(usbhid_submit_report);
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
@@ -465,7 +485,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return -1;
if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- warn("event field not found");
+ dev_warn(&dev->dev, "event field not found\n");
return -1;
}
@@ -568,7 +588,7 @@ void usbhid_init_reports(struct hid_device *hid)
}
if (err)
- warn("timeout initializing reports");
+ dev_warn(&hid->dev, "timeout initializing reports\n");
}
/*
@@ -598,7 +618,7 @@ static int hid_find_field_early(struct hid_device *hid, unsigned int page,
return -1;
}
-static void usbhid_set_leds(struct hid_device *hid)
+void usbhid_set_leds(struct hid_device *hid)
{
struct hid_field *field;
int offset;
@@ -608,6 +628,7 @@ static void usbhid_set_leds(struct hid_device *hid)
usbhid_submit_report(hid, field->report, USB_DIR_OUT);
}
}
+EXPORT_SYMBOL_GPL(usbhid_set_leds);
/*
* Traverse the supplied list of reports and find the longest
@@ -675,43 +696,16 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
-/*
- * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
- * to "operational". Without this, the ps3 controller will not report any
- * events.
- */
-static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
-{
- int result;
- char *buf = kmalloc(18, GFP_KERNEL);
-
- if (!buf)
- return;
-
- result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- HID_REQ_GET_REPORT,
- USB_DIR_IN | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE,
- (3 << 8) | 0xf2, ifnum, buf, 17,
- USB_CTRL_GET_TIMEOUT);
-
- if (result < 0)
- err_hid("%s failed: %d\n", __func__, result);
-
- kfree(buf);
-}
-
-static struct hid_device *usb_hid_configure(struct usb_interface *intf)
+static int usbhid_parse(struct hid_device *hid)
{
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_host_interface *interface = intf->cur_altsetting;
struct usb_device *dev = interface_to_usbdev (intf);
struct hid_descriptor *hdesc;
- struct hid_device *hid;
u32 quirks = 0;
- unsigned int insize = 0, rsize = 0;
+ unsigned int rsize = 0;
char *rdesc;
- int n, len;
- struct usbhid_device *usbhid;
+ int ret, n;
quirks = usbhid_lookup_quirk(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
@@ -724,63 +718,75 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
quirks |= HID_QUIRK_NOGET;
}
- if (quirks & HID_QUIRK_IGNORE)
- return NULL;
-
- if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
- (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
- return NULL;
-
-
if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
(!interface->desc.bNumEndpoints ||
usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
dbg_hid("class descriptor not present\n");
- return NULL;
+ return -ENODEV;
}
+ hid->version = le16_to_cpu(hdesc->bcdHID);
+ hid->country = hdesc->bCountryCode;
+
for (n = 0; n < hdesc->bNumDescriptors; n++)
if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT)
rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
dbg_hid("weird size of report descriptor (%u)\n", rsize);
- return NULL;
+ return -EINVAL;
}
if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) {
dbg_hid("couldn't allocate rdesc memory\n");
- return NULL;
+ return -ENOMEM;
}
hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
- if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
+ ret = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber,
+ HID_DT_REPORT, rdesc, rsize);
+ if (ret < 0) {
dbg_hid("reading report descriptor failed\n");
kfree(rdesc);
- return NULL;
+ goto err;
}
- usbhid_fixup_report_descriptor(le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct), rdesc,
- rsize, rdesc_quirks_param);
-
dbg_hid("report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
dbg_hid_line(" %02x", (unsigned char) rdesc[n]);
dbg_hid_line("\n");
- if (!(hid = hid_parse_report(rdesc, n))) {
+ ret = hid_parse_report(hid, rdesc, rsize);
+ kfree(rdesc);
+ if (ret) {
dbg_hid("parsing report descriptor failed\n");
- kfree(rdesc);
- return NULL;
+ goto err;
}
- kfree(rdesc);
hid->quirks = quirks;
- if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL)))
- goto fail_no_usbhid;
+ return 0;
+err:
+ return ret;
+}
+
+static int usbhid_start(struct hid_device *hid)
+{
+ struct usb_interface *intf = to_usb_interface(hid->dev.parent);
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usbhid_device *usbhid;
+ unsigned int n, insize = 0;
+ int ret;
+
+ WARN_ON(hid->driver_data);
+
+ usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL);
+ if (usbhid == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
hid->driver_data = usbhid;
usbhid->hid = hid;
@@ -799,28 +805,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
insize = HID_MAX_BUFFER_SIZE;
if (hid_alloc_buffers(dev, hid)) {
- hid_free_buffers(dev, hid);
+ ret = -ENOMEM;
goto fail;
}
- hid->name[0] = 0;
-
- if (dev->manufacturer)
- strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
-
- if (dev->product) {
- if (dev->manufacturer)
- strlcat(hid->name, " ", sizeof(hid->name));
- strlcat(hid->name, dev->product, sizeof(hid->name));
- }
-
- if (!strlen(hid->name))
- snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct));
-
for (n = 0; n < interface->desc.bNumEndpoints; n++) {
-
struct usb_endpoint_descriptor *endpoint;
int pipe;
int interval;
@@ -832,7 +821,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
interval = endpoint->bInterval;
/* Some vendors give fullspeed interval on highspeed devides */
- if (quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
+ if (hid->quirks & HID_QUIRK_FULLSPEED_INTERVAL &&
dev->speed == USB_SPEED_HIGH) {
interval = fls(endpoint->bInterval*8);
printk(KERN_INFO "%s: Fixing fullspeed to highspeed interval: %d -> %d\n",
@@ -843,6 +832,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval;
+ ret = -ENOMEM;
if (usb_endpoint_dir_in(endpoint)) {
if (usbhid->urbin)
continue;
@@ -868,6 +858,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (!usbhid->urbin) {
err_hid("couldn't find an input interrupt endpoint");
+ ret = -ENODEV;
goto fail;
}
@@ -879,44 +870,25 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
spin_lock_init(&usbhid->outlock);
spin_lock_init(&usbhid->ctrllock);
- hid->version = le16_to_cpu(hdesc->bcdHID);
- hid->country = hdesc->bCountryCode;
- hid->dev = &intf->dev;
usbhid->intf = intf;
usbhid->ifnum = interface->desc.bInterfaceNumber;
- hid->bus = BUS_USB;
- hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
- hid->product = le16_to_cpu(dev->descriptor.idProduct);
-
- usb_make_path(dev, hid->phys, sizeof(hid->phys));
- strlcat(hid->phys, "/input", sizeof(hid->phys));
- len = strlen(hid->phys);
- if (len < sizeof(hid->phys) - 1)
- snprintf(hid->phys + len, sizeof(hid->phys) - len,
- "%d", intf->altsetting[0].desc.bInterfaceNumber);
-
- if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
- hid->uniq[0] = 0;
-
usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL);
- if (!usbhid->urbctrl)
+ if (!usbhid->urbctrl) {
+ ret = -ENOMEM;
goto fail;
+ }
usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr,
usbhid->ctrlbuf, 1, hid_ctrl, hid);
usbhid->urbctrl->setup_dma = usbhid->cr_dma;
usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
- hid->hidinput_input_event = usb_hidinput_input_event;
- hid->hid_open = usbhid_open;
- hid->hid_close = usbhid_close;
-#ifdef CONFIG_USB_HIDDEV
- hid->hiddev_hid_event = hiddev_hid_event;
- hid->hiddev_report_event = hiddev_report_event;
-#endif
- hid->hid_output_raw_report = usbhid_output_raw_report;
- return hid;
+
+ usbhid_init_reports(hid);
+ hid_dump_device(hid);
+
+ return 0;
fail:
usb_free_urb(usbhid->urbin);
@@ -924,24 +896,18 @@ fail:
usb_free_urb(usbhid->urbctrl);
hid_free_buffers(dev, hid);
kfree(usbhid);
-fail_no_usbhid:
- hid_free_device(hid);
-
- return NULL;
+err:
+ return ret;
}
-static void hid_disconnect(struct usb_interface *intf)
+static void usbhid_stop(struct hid_device *hid)
{
- struct hid_device *hid = usb_get_intfdata (intf);
- struct usbhid_device *usbhid;
+ struct usbhid_device *usbhid = hid->driver_data;
- if (!hid)
+ if (WARN_ON(!usbhid))
return;
- usbhid = hid->driver_data;
-
spin_lock_irq(&usbhid->inlock); /* Sync with error handler */
- usb_set_intfdata(intf, NULL);
set_bit(HID_DISCONNECTED, &usbhid->iofl);
spin_unlock_irq(&usbhid->inlock);
usb_kill_urb(usbhid->urbin);
@@ -958,86 +924,100 @@ static void hid_disconnect(struct usb_interface *intf)
if (hid->claimed & HID_CLAIMED_HIDRAW)
hidraw_disconnect(hid);
+ hid->claimed = 0;
+
usb_free_urb(usbhid->urbin);
usb_free_urb(usbhid->urbctrl);
usb_free_urb(usbhid->urbout);
hid_free_buffers(hid_to_usb_dev(hid), hid);
kfree(usbhid);
- hid_free_device(hid);
+ hid->driver_data = NULL;
}
+static struct hid_ll_driver usb_hid_driver = {
+ .parse = usbhid_parse,
+ .start = usbhid_start,
+ .stop = usbhid_stop,
+ .open = usbhid_open,
+ .close = usbhid_close,
+ .hidinput_input_event = usb_hidinput_input_event,
+};
+
static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
+ struct usb_device *dev = interface_to_usbdev(intf);
struct hid_device *hid;
- char path[64];
- int i;
- char *c;
+ size_t len;
+ int ret;
dbg_hid("HID probe called for ifnum %d\n",
intf->altsetting->desc.bInterfaceNumber);
- if (!(hid = usb_hid_configure(intf)))
- return -ENODEV;
-
- usbhid_init_reports(hid);
- hid_dump_device(hid);
- if (hid->quirks & HID_QUIRK_RESET_LEDS)
- usbhid_set_leds(hid);
-
- if (!hidinput_connect(hid))
- hid->claimed |= HID_CLAIMED_INPUT;
- if (!hiddev_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDDEV;
- if (!hidraw_connect(hid))
- hid->claimed |= HID_CLAIMED_HIDRAW;
+ hid = hid_allocate_device();
+ if (IS_ERR(hid))
+ return PTR_ERR(hid);
usb_set_intfdata(intf, hid);
+ hid->ll_driver = &usb_hid_driver;
+ hid->hid_output_raw_report = usbhid_output_raw_report;
+ hid->ff_init = hid_pidff_init;
+#ifdef CONFIG_USB_HIDDEV
+ hid->hiddev_connect = hiddev_connect;
+ hid->hiddev_hid_event = hiddev_hid_event;
+ hid->hiddev_report_event = hiddev_report_event;
+#endif
+ hid->dev.parent = &intf->dev;
+ hid->bus = BUS_USB;
+ hid->vendor = le16_to_cpu(dev->descriptor.idVendor);
+ hid->product = le16_to_cpu(dev->descriptor.idProduct);
+ hid->name[0] = 0;
- if (!hid->claimed) {
- printk ("HID device claimed by neither input, hiddev nor hidraw\n");
- hid_disconnect(intf);
- return -ENODEV;
+ if (dev->manufacturer)
+ strlcpy(hid->name, dev->manufacturer, sizeof(hid->name));
+
+ if (dev->product) {
+ if (dev->manufacturer)
+ strlcat(hid->name, " ", sizeof(hid->name));
+ strlcat(hid->name, dev->product, sizeof(hid->name));
}
- if ((hid->claimed & HID_CLAIMED_INPUT))
- hid_ff_init(hid);
+ if (!strlen(hid->name))
+ snprintf(hid->name, sizeof(hid->name), "HID %04x:%04x",
+ le16_to_cpu(dev->descriptor.idVendor),
+ le16_to_cpu(dev->descriptor.idProduct));
- if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
- hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
- intf->cur_altsetting->desc.bInterfaceNumber);
+ usb_make_path(dev, hid->phys, sizeof(hid->phys));
+ strlcat(hid->phys, "/input", sizeof(hid->phys));
+ len = strlen(hid->phys);
+ if (len < sizeof(hid->phys) - 1)
+ snprintf(hid->phys + len, sizeof(hid->phys) - len,
+ "%d", intf->altsetting[0].desc.bInterfaceNumber);
- printk(KERN_INFO);
+ if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0)
+ hid->uniq[0] = 0;
- if (hid->claimed & HID_CLAIMED_INPUT)
- printk("input");
- if ((hid->claimed & HID_CLAIMED_INPUT) && ((hid->claimed & HID_CLAIMED_HIDDEV) ||
- hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDDEV)
- printk("hiddev%d", hid->minor);
- if ((hid->claimed & HID_CLAIMED_INPUT) && (hid->claimed & HID_CLAIMED_HIDDEV) &&
- (hid->claimed & HID_CLAIMED_HIDRAW))
- printk(",");
- if (hid->claimed & HID_CLAIMED_HIDRAW)
- printk("hidraw%d", ((struct hidraw*)hid->hidraw)->minor);
-
- c = "Device";
- for (i = 0; i < hid->maxcollection; i++) {
- if (hid->collection[i].type == HID_COLLECTION_APPLICATION &&
- (hid->collection[i].usage & HID_USAGE_PAGE) == HID_UP_GENDESK &&
- (hid->collection[i].usage & 0xffff) < ARRAY_SIZE(hid_types)) {
- c = hid_types[hid->collection[i].usage & 0xffff];
- break;
- }
+ ret = hid_add_device(hid);
+ if (ret) {
+ if (ret != -ENODEV)
+ dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+ goto err;
}
- usb_make_path(interface_to_usbdev(intf), path, 63);
+ return 0;
+err:
+ hid_destroy_device(hid);
+ return ret;
+}
- printk(": USB HID v%x.%02x %s [%s] on %s\n",
- hid->version >> 8, hid->version & 0xff, c, hid->name, path);
+static void hid_disconnect(struct usb_interface *intf)
+{
+ struct hid_device *hid = usb_get_intfdata(intf);
- return 0;
+ if (WARN_ON(!hid))
+ return;
+
+ hid_destroy_device(hid);
}
static int hid_suspend(struct usb_interface *intf, pm_message_t message)
@@ -1107,9 +1087,22 @@ static struct usb_driver hid_driver = {
.supports_autosuspend = 1,
};
+static const struct hid_device_id hid_usb_table[] = {
+ { HID_USB_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+
+static struct hid_driver hid_usb_driver = {
+ .name = "generic-usb",
+ .id_table = hid_usb_table,
+};
+
static int __init hid_init(void)
{
int retval;
+ retval = hid_register_driver(&hid_usb_driver);
+ if (retval)
+ goto hid_register_fail;
retval = usbhid_quirks_init(quirks_param);
if (retval)
goto usbhid_quirks_init_fail;
@@ -1119,7 +1112,8 @@ static int __init hid_init(void)
retval = usb_register(&hid_driver);
if (retval)
goto usb_register_fail;
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return 0;
usb_register_fail:
@@ -1127,6 +1121,8 @@ usb_register_fail:
hiddev_init_fail:
usbhid_quirks_exit();
usbhid_quirks_init_fail:
+ hid_unregister_driver(&hid_usb_driver);
+hid_register_fail:
return retval;
}
@@ -1135,6 +1131,7 @@ static void __exit hid_exit(void)
usb_deregister(&hid_driver);
hiddev_exit();
usbhid_quirks_exit();
+ hid_unregister_driver(&hid_usb_driver);
}
module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-ff.c b/drivers/hid/usbhid/hid-ff.c
deleted file mode 100644
index 1d0dac52f16..00000000000
--- a/drivers/hid/usbhid/hid-ff.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Force feedback support for hid devices.
- * Not all hid devices use the same protocol. For example, some use PID,
- * other use their own proprietary procotol.
- *
- * Copyright (c) 2002-2004 Johann Deneux
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <johann.deneux@it.uu.se>
- */
-
-#include <linux/input.h>
-
-#undef DEBUG
-#include <linux/usb.h>
-
-#include <linux/hid.h>
-#include "usbhid.h"
-
-/*
- * This table contains pointers to initializers. To add support for new
- * devices, you need to add the USB vendor and product ids here.
- */
-struct hid_ff_initializer {
- u16 idVendor;
- u16 idProduct;
- int (*init)(struct hid_device*);
-};
-
-/*
- * We try pidff when no other driver is found because PID is the
- * standards compliant way of implementing force feedback in HID.
- * pidff_init() will quickly abort if the device doesn't appear to
- * be a PID device
- */
-static struct hid_ff_initializer inits[] = {
-#ifdef CONFIG_LOGITECH_FF
- { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
- { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
- { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
- { 0x46d, 0xc286, hid_lgff_init }, /* Logitech Force 3D Pro Joystick */
- { 0x46d, 0xc294, hid_lgff_init }, /* Logitech Formula Force EX */
- { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
- { 0x46d, 0xca03, hid_lgff_init }, /* Logitech MOMO force wheel */
-#endif
-#ifdef CONFIG_LOGIRUMBLEPAD2_FF
- { 0x46d, 0xc218, hid_lg2ff_init }, /* Logitech Rumblepad 2 */
-#endif
-#ifdef CONFIG_PANTHERLORD_FF
- { 0x810, 0x0001, hid_plff_init }, /* "Twin USB Joystick" */
- { 0xe8f, 0x0003, hid_plff_init }, /* "GreenAsia Inc. USB Joystick " */
-#endif
-#ifdef CONFIG_THRUSTMASTER_FF
- { 0x44f, 0xb300, hid_tmff_init },
- { 0x44f, 0xb304, hid_tmff_init },
- { 0x44f, 0xb651, hid_tmff_init }, /* FGT Rumble Force Wheel */
- { 0x44f, 0xb654, hid_tmff_init }, /* FGT Force Feedback Wheel */
-#endif
-#ifdef CONFIG_ZEROPLUS_FF
- { 0xc12, 0x0005, hid_zpff_init },
- { 0xc12, 0x0030, hid_zpff_init },
-#endif
- { 0, 0, hid_pidff_init} /* Matches anything */
-};
-
-int hid_ff_init(struct hid_device* hid)
-{
- struct hid_ff_initializer *init;
- int vendor = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idVendor);
- int product = le16_to_cpu(hid_to_usb_dev(hid)->descriptor.idProduct);
-
- for (init = inits; init->idVendor; init++)
- if (init->idVendor == vendor && init->idProduct == product)
- break;
-
- return init->init(hid);
-}
-EXPORT_SYMBOL_GPL(hid_ff_init);
-
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 011326178c0..484e3eec2f8 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -397,7 +397,6 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband);
- usbhid_wait_io(pidff->hid);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
USB_DIR_OUT);
}
@@ -512,7 +511,6 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
- usbhid_wait_io(pidff->hid);
usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
USB_DIR_OUT);
}
@@ -548,6 +546,9 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
int pid_id = pidff->pid_id[effect_id];
debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+ /* Wait for the queue to clear. We do not want a full fifo to
+ prevent the effect removal. */
+ usbhid_wait_io(pidff->hid);
pidff_playback_pid(pidff, pid_id, 0);
pidff_erase_pid(pidff, pid_id);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index b15f8824963..47ebe045f9b 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -17,412 +17,7 @@
#include <linux/hid.h>
-#define USB_VENDOR_ID_A4TECH 0x09da
-#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
-#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a
-
-#define USB_VENDOR_ID_AASHIMA 0x06d6
-#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025
-#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026
-
-#define USB_VENDOR_ID_ACECAD 0x0460
-#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
-#define USB_DEVICE_ID_ACECAD_302 0x0008
-
-#define USB_VENDOR_ID_ADS_TECH 0x06e1
-#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155
-
-#define USB_VENDOR_ID_AFATECH 0x15a4
-#define USB_DEVICE_ID_AFATECH_AF9016 0x9016
-
-#define USB_VENDOR_ID_AIPTEK 0x08ca
-#define USB_DEVICE_ID_AIPTEK_01 0x0001
-#define USB_DEVICE_ID_AIPTEK_10 0x0010
-#define USB_DEVICE_ID_AIPTEK_20 0x0020
-#define USB_DEVICE_ID_AIPTEK_21 0x0021
-#define USB_DEVICE_ID_AIPTEK_22 0x0022
-#define USB_DEVICE_ID_AIPTEK_23 0x0023
-#define USB_DEVICE_ID_AIPTEK_24 0x0024
-
-#define USB_VENDOR_ID_AIRCABLE 0x16CA
-#define USB_DEVICE_ID_AIRCABLE1 0x1502
-
-#define USB_VENDOR_ID_ALCOR 0x058f
-#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
-
-#define USB_VENDOR_ID_ALPS 0x0433
-#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101
-
-#define USB_VENDOR_ID_APPLE 0x05ac
-#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f
-#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214
-#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215
-#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216
-#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217
-#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218
-#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219
-#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a
-#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b
-#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c
-#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220
-#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221
-#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
-#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
-#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a
-#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d
-#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
-#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
-#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
-#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
-#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
-
-#define USB_VENDOR_ID_ASUS 0x0b05
-#define USB_DEVICE_ID_ASUS_LCM 0x1726
-
-#define USB_VENDOR_ID_ATEN 0x0557
-#define USB_DEVICE_ID_ATEN_UC100KM 0x2004
-#define USB_DEVICE_ID_ATEN_CS124U 0x2202
-#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204
-#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
-#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
-
-#define USB_VENDOR_ID_BELKIN 0x050d
-#define USB_DEVICE_ID_FLIP_KVM 0x3201
-
-#define USB_VENDOR_ID_BERKSHIRE 0x0c98
-#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
-
-#define USB_VENDOR_ID_CHERRY 0x046a
-#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023
-
-#define USB_VENDOR_ID_CHIC 0x05fe
-#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014
-
-#define USB_VENDOR_ID_CIDC 0x1677
-
-#define USB_VENDOR_ID_CMEDIA 0x0d8c
-#define USB_DEVICE_ID_CM109 0x000e
-
-#define USB_VENDOR_ID_CODEMERCS 0x07c0
-#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500
-#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff
-
-#define USB_VENDOR_ID_CYGNAL 0x10c4
-#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
-
-#define USB_VENDOR_ID_CYPRESS 0x04b4
-#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
-#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
-#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
-#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
-#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
-
-#define USB_VENDOR_ID_DELL 0x413c
-#define USB_DEVICE_ID_DELL_W7658 0x2005
-
-#define USB_VENDOR_ID_DELORME 0x1163
-#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100
-#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200
-
-#define USB_VENDOR_ID_DMI 0x0c0b
-#define USB_DEVICE_ID_DMI_ENC 0x5fab
-
-#define USB_VENDOR_ID_ELO 0x04E7
-#define USB_DEVICE_ID_ELO_TS2700 0x0020
-
-#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
-#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
-
-#define USB_VENDOR_ID_EZKEY 0x0518
-#define USB_DEVICE_ID_BTC_8193 0x0002
-
-#define USB_VENDOR_ID_GAMERON 0x0810
-#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001
-
-#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
-
-#define USB_VENDOR_ID_GLAB 0x06c2
-#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
-#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
-#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
-#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
-#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
-#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
-#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
-#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
-
-#define USB_VENDOR_ID_GOTOP 0x08f2
-#define USB_DEVICE_ID_SUPER_Q2 0x007f
-#define USB_DEVICE_ID_GOGOPEN 0x00ce
-#define USB_DEVICE_ID_PENPOWER 0x00f4
-
-#define USB_VENDOR_ID_GRETAGMACBETH 0x0971
-#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005
-
-#define USB_VENDOR_ID_GRIFFIN 0x077d
-#define USB_DEVICE_ID_POWERMATE 0x0410
-#define USB_DEVICE_ID_SOUNDKNOB 0x04AA
-
-#define USB_VENDOR_ID_GTCO 0x078c
-#define USB_DEVICE_ID_GTCO_90 0x0090
-#define USB_DEVICE_ID_GTCO_100 0x0100
-#define USB_DEVICE_ID_GTCO_101 0x0101
-#define USB_DEVICE_ID_GTCO_103 0x0103
-#define USB_DEVICE_ID_GTCO_104 0x0104
-#define USB_DEVICE_ID_GTCO_105 0x0105
-#define USB_DEVICE_ID_GTCO_106 0x0106
-#define USB_DEVICE_ID_GTCO_107 0x0107
-#define USB_DEVICE_ID_GTCO_108 0x0108
-#define USB_DEVICE_ID_GTCO_200 0x0200
-#define USB_DEVICE_ID_GTCO_201 0x0201
-#define USB_DEVICE_ID_GTCO_202 0x0202
-#define USB_DEVICE_ID_GTCO_203 0x0203
-#define USB_DEVICE_ID_GTCO_204 0x0204
-#define USB_DEVICE_ID_GTCO_205 0x0205
-#define USB_DEVICE_ID_GTCO_206 0x0206
-#define USB_DEVICE_ID_GTCO_207 0x0207
-#define USB_DEVICE_ID_GTCO_300 0x0300
-#define USB_DEVICE_ID_GTCO_301 0x0301
-#define USB_DEVICE_ID_GTCO_302 0x0302
-#define USB_DEVICE_ID_GTCO_303 0x0303
-#define USB_DEVICE_ID_GTCO_304 0x0304
-#define USB_DEVICE_ID_GTCO_305 0x0305
-#define USB_DEVICE_ID_GTCO_306 0x0306
-#define USB_DEVICE_ID_GTCO_307 0x0307
-#define USB_DEVICE_ID_GTCO_308 0x0308
-#define USB_DEVICE_ID_GTCO_309 0x0309
-#define USB_DEVICE_ID_GTCO_400 0x0400
-#define USB_DEVICE_ID_GTCO_401 0x0401
-#define USB_DEVICE_ID_GTCO_402 0x0402
-#define USB_DEVICE_ID_GTCO_403 0x0403
-#define USB_DEVICE_ID_GTCO_404 0x0404
-#define USB_DEVICE_ID_GTCO_405 0x0405
-#define USB_DEVICE_ID_GTCO_500 0x0500
-#define USB_DEVICE_ID_GTCO_501 0x0501
-#define USB_DEVICE_ID_GTCO_502 0x0502
-#define USB_DEVICE_ID_GTCO_503 0x0503
-#define USB_DEVICE_ID_GTCO_504 0x0504
-#define USB_DEVICE_ID_GTCO_1000 0x1000
-#define USB_DEVICE_ID_GTCO_1001 0x1001
-#define USB_DEVICE_ID_GTCO_1002 0x1002
-#define USB_DEVICE_ID_GTCO_1003 0x1003
-#define USB_DEVICE_ID_GTCO_1004 0x1004
-#define USB_DEVICE_ID_GTCO_1005 0x1005
-#define USB_DEVICE_ID_GTCO_1006 0x1006
-#define USB_DEVICE_ID_GTCO_1007 0x1007
-#define USB_VENDOR_ID_HAPP 0x078b
-#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
-#define USB_DEVICE_ID_UGCI_FLYING 0x0020
-#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030
-
-#define USB_VENDOR_ID_IMATION 0x0718
-#define USB_DEVICE_ID_DISC_STAKKA 0xd000
-
-#define USB_VENDOR_ID_KBGEAR 0x084e
-#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
-
-#define USB_VENDOR_ID_LD 0x0f11
-#define USB_DEVICE_ID_LD_CASSY 0x1000
-#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
-#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020
-#define USB_DEVICE_ID_LD_JWM 0x1080
-#define USB_DEVICE_ID_LD_DMMP 0x1081
-#define USB_DEVICE_ID_LD_UMIP 0x1090
-#define USB_DEVICE_ID_LD_XRAY1 0x1100
-#define USB_DEVICE_ID_LD_XRAY2 0x1101
-#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200
-#define USB_DEVICE_ID_LD_COM3LAB 0x2000
-#define USB_DEVICE_ID_LD_TELEPORT 0x2010
-#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020
-#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030
-#define USB_DEVICE_ID_LD_MACHINETEST 0x2040
-
-#define USB_VENDOR_ID_LOGITECH 0x046d
-#define USB_DEVICE_ID_LOGITECH_LX3 0xc044
-#define USB_DEVICE_ID_LOGITECH_V150 0xc047
-#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
-#define USB_DEVICE_ID_LOGITECH_HARMONY 0xc110
-#define USB_DEVICE_ID_LOGITECH_HARMONY_2 0xc111
-#define USB_DEVICE_ID_LOGITECH_HARMONY_3 0xc112
-#define USB_DEVICE_ID_LOGITECH_HARMONY_4 0xc113
-#define USB_DEVICE_ID_LOGITECH_HARMONY_5 0xc114
-#define USB_DEVICE_ID_LOGITECH_HARMONY_6 0xc115
-#define USB_DEVICE_ID_LOGITECH_HARMONY_7 0xc116
-#define USB_DEVICE_ID_LOGITECH_HARMONY_8 0xc117
-#define USB_DEVICE_ID_LOGITECH_HARMONY_9 0xc118
-#define USB_DEVICE_ID_LOGITECH_HARMONY_10 0xc119
-#define USB_DEVICE_ID_LOGITECH_HARMONY_11 0xc11a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_12 0xc11b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_13 0xc11c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_14 0xc11d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_15 0xc11e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_16 0xc11f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_17 0xc120
-#define USB_DEVICE_ID_LOGITECH_HARMONY_18 0xc121
-#define USB_DEVICE_ID_LOGITECH_HARMONY_19 0xc122
-#define USB_DEVICE_ID_LOGITECH_HARMONY_20 0xc123
-#define USB_DEVICE_ID_LOGITECH_HARMONY_21 0xc124
-#define USB_DEVICE_ID_LOGITECH_HARMONY_22 0xc125
-#define USB_DEVICE_ID_LOGITECH_HARMONY_23 0xc126
-#define USB_DEVICE_ID_LOGITECH_HARMONY_24 0xc127
-#define USB_DEVICE_ID_LOGITECH_HARMONY_25 0xc128
-#define USB_DEVICE_ID_LOGITECH_HARMONY_26 0xc129
-#define USB_DEVICE_ID_LOGITECH_HARMONY_27 0xc12a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_28 0xc12b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_29 0xc12c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_30 0xc12d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_31 0xc12e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_32 0xc12f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_33 0xc130
-#define USB_DEVICE_ID_LOGITECH_HARMONY_34 0xc131
-#define USB_DEVICE_ID_LOGITECH_HARMONY_35 0xc132
-#define USB_DEVICE_ID_LOGITECH_HARMONY_36 0xc133
-#define USB_DEVICE_ID_LOGITECH_HARMONY_37 0xc134
-#define USB_DEVICE_ID_LOGITECH_HARMONY_38 0xc135
-#define USB_DEVICE_ID_LOGITECH_HARMONY_39 0xc136
-#define USB_DEVICE_ID_LOGITECH_HARMONY_40 0xc137
-#define USB_DEVICE_ID_LOGITECH_HARMONY_41 0xc138
-#define USB_DEVICE_ID_LOGITECH_HARMONY_42 0xc139
-#define USB_DEVICE_ID_LOGITECH_HARMONY_43 0xc13a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_44 0xc13b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_45 0xc13c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_46 0xc13d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_47 0xc13e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_48 0xc13f
-#define USB_DEVICE_ID_LOGITECH_HARMONY_49 0xc140
-#define USB_DEVICE_ID_LOGITECH_HARMONY_50 0xc141
-#define USB_DEVICE_ID_LOGITECH_HARMONY_51 0xc142
-#define USB_DEVICE_ID_LOGITECH_HARMONY_52 0xc143
-#define USB_DEVICE_ID_LOGITECH_HARMONY_53 0xc144
-#define USB_DEVICE_ID_LOGITECH_HARMONY_54 0xc145
-#define USB_DEVICE_ID_LOGITECH_HARMONY_55 0xc146
-#define USB_DEVICE_ID_LOGITECH_HARMONY_56 0xc147
-#define USB_DEVICE_ID_LOGITECH_HARMONY_57 0xc148
-#define USB_DEVICE_ID_LOGITECH_HARMONY_58 0xc149
-#define USB_DEVICE_ID_LOGITECH_HARMONY_59 0xc14a
-#define USB_DEVICE_ID_LOGITECH_HARMONY_60 0xc14b
-#define USB_DEVICE_ID_LOGITECH_HARMONY_61 0xc14c
-#define USB_DEVICE_ID_LOGITECH_HARMONY_62 0xc14d
-#define USB_DEVICE_ID_LOGITECH_HARMONY_63 0xc14e
-#define USB_DEVICE_ID_LOGITECH_HARMONY_64 0xc14f
-#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215
-#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
-#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
-#define USB_DEVICE_ID_LOGITECH_KBD 0xc311
-#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
-#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
-#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
-#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
-#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
-#define USB_DEVICE_ID_DINOVO_EDGE 0xc714
-#define USB_DEVICE_ID_DINOVO_MINI 0xc71f
-
-#define USB_VENDOR_ID_MCC 0x09db
-#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076
-#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a
-
-#define USB_VENDOR_ID_MGE 0x0463
-#define USB_DEVICE_ID_MGE_UPS 0xffff
-#define USB_DEVICE_ID_MGE_UPS1 0x0001
-
-#define USB_VENDOR_ID_MICROCHIP 0x04d8
-#define USB_DEVICE_ID_PICKIT1 0x0032
-#define USB_DEVICE_ID_PICKIT2 0x0033
-
-#define USB_VENDOR_ID_MICROSOFT 0x045e
-#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
-#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
-#define USB_DEVICE_ID_DESKTOP_RECV_1028 0x00f9
-#define USB_DEVICE_ID_MS_NE4K 0x00db
-#define USB_DEVICE_ID_MS_LK6K 0x00f9
-
-#define USB_VENDOR_ID_MONTEREY 0x0566
-#define USB_DEVICE_ID_GENIUS_KB29E 0x3004
-
-#define USB_VENDOR_ID_NCR 0x0404
-#define USB_DEVICE_ID_NCR_FIRST 0x0300
-#define USB_DEVICE_ID_NCR_LAST 0x03ff
-
-#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400
-#define USB_DEVICE_ID_N_S_HARMONY 0xc359
-
-#define USB_VENDOR_ID_NATSU 0x08b7
-#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001
-
-#define USB_VENDOR_ID_NEC 0x073e
-#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
-
-#define USB_VENDOR_ID_ONTRAK 0x0a07
-#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
-
-#define USB_VENDOR_ID_PANJIT 0x134c
-
-#define USB_VENDOR_ID_PANTHERLORD 0x0810
-#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001
-
-#define USB_VENDOR_ID_PETALYNX 0x18b1
-#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037
-
-#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
-#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
-
-#define USB_VENDOR_ID_SAITEK 0x06a3
-#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
-
-#define USB_VENDOR_ID_SAMSUNG 0x0419
-#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
-
-#define USB_VENDOR_ID_SONY 0x054c
-#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
-
-#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
-#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD 0x0038
-
-#define USB_VENDOR_ID_SUN 0x0430
-#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
-
-#define USB_VENDOR_ID_SUNPLUS 0x04fc
-#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8
-
-#define USB_VENDOR_ID_TOPMAX 0x0663
-#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103
-
-#define USB_VENDOR_ID_TURBOX 0x062a
-#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
-
-#define USB_VENDOR_ID_VERNIER 0x08f7
-#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
-#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
-#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
-#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
-#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006
-
-#define USB_VENDOR_ID_WACOM 0x056a
-
-#define USB_VENDOR_ID_WISEGROUP 0x0925
-#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
-#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
-#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
-#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800
-#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
-
-#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
-#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802
-
-#define USB_VENDOR_ID_YEALINK 0x6993
-#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
-
-#define USB_VENDOR_ID_KYE 0x0458
-#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
+#include "../hid-ids.h"
/*
* Alphabetically sorted blacklist by quirk type.
@@ -433,18 +28,10 @@ static const struct hid_blacklist {
__u16 idProduct;
__u32 quirks;
} hid_blacklist[] = {
-
- { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU, HID_QUIRK_2WHEEL_MOUSE_HACK_7 },
- { USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D, HID_QUIRK_2WHEEL_MOUSE_HACK_B8 },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE, HID_QUIRK_2WHEEL_MOUSE_HACK_5 },
-
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
-
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_AASHIMA, USB_DEVICE_ID_AASHIMA_PREDATOR, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_ALPS, USB_DEVICE_ID_IBM_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -453,169 +40,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RUMBLEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP, HID_QUIRK_DUPLICATE_USAGES },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE, HID_QUIRK_DUPLICATE_USAGES },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI, HID_QUIRK_DUPLICATE_USAGES },
-
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
- { USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM, HID_QUIRK_HIDDEV },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
- { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_HIDDEV | HID_QUIRK_IGNORE_HIDINPUT },
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV, HID_QUIRK_HIDINPUT },
-
- { USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193, HID_QUIRK_HWHEEL_WHEEL_INVERT },
-
- { USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_LCM, HID_QUIRK_IGNORE},
- { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CIDC, 0x0103, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GENERAL_TOUCH, 0x0001, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GENERAL_TOUCH, 0x0002, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GENERAL_TOUCH, 0x0003, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GENERAL_TOUCH, 0x0004, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2, HID_QUIRK_IGNORE },
-
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500, HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL | HID_QUIRK_LOGITECH_EXPANDED_KEYMAP },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_LX3, HID_QUIRK_INVERT_HWHEEL },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_V150, HID_QUIRK_INVERT_HWHEEL },
-
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K, HID_QUIRK_MICROSOFT_KEYS },
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K, HID_QUIRK_MICROSOFT_KEYS },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
-
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER | HID_QUIRK_HIDDEV },
-
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -623,144 +52,13 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0, HID_QUIRK_NOGET },
- { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_QUAD_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_APPLE_ISO_KEYBOARD},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI, HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS, HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
-
- { USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KBD, HID_QUIRK_RESET_LEDS },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_2, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_3, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_4, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_5, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_6, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_7, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_8, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_9, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_10, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_11, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_12, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_13, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_14, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_15, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_16, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_17, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_18, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_19, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_20, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_21, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_22, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_23, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_24, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_25, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_26, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_27, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_28, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_29, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_31, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_32, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_33, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_34, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_35, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_36, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_37, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_38, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_39, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_40, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_41, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_42, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_43, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_44, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_45, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_46, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_47, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_48, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_49, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_50, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_51, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_52, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_53, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_54, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_55, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_56, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_57, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_58, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_59, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_60, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_61, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_62, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_63, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_64, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560, HID_QUIRK_IGNORE },
-
- { 0, 0 }
-};
-
-/* Quirks for devices which require report descriptor fixup go here */
-static const struct hid_rdesc_blacklist {
- __u16 idVendor;
- __u16 idProduct;
- __u32 quirks;
-} hid_rdesc_blacklist[] = {
-
- { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_RDESC_CYMOTION },
-
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER, HID_QUIRK_RDESC_LOGITECH },
- { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2, HID_QUIRK_RDESC_LOGITECH },
- { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_DESKTOP_RECV_1028, HID_QUIRK_RDESC_MICROSOFT_RECV_1028 },
-
- { USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E, HID_QUIRK_RDESC_BUTTON_CONSUMER },
-
- { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_RDESC_MACBOOK_JIS },
-
- { USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE, HID_QUIRK_RDESC_PETALYNX },
-
- { USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE, HID_QUIRK_RDESC_SAMSUNG_REMOTE },
-
- { USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP, HID_QUIRK_RDESC_SUNPLUS_WDESKTOP },
-
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
- { USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_RDESC_SWAPPED_MIN_MAX },
+ { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ 0, 0 }
};
@@ -974,16 +272,6 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
u32 quirks = 0;
const struct hid_blacklist *bl_entry = NULL;
- /* Ignore all Wacom devices */
- if (idVendor == USB_VENDOR_ID_WACOM)
- return HID_QUIRK_IGNORE;
-
- /* ignore all Code Mercenaries IOWarrior devices */
- if (idVendor == USB_VENDOR_ID_CODEMERCS)
- if (idProduct >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST &&
- idProduct <= USB_DEVICE_ID_CODEMERCS_IOW_LAST)
- return HID_QUIRK_IGNORE;
-
/* NCR devices must not be queried for reports */
if (idVendor == USB_VENDOR_ID_NCR &&
idProduct >= USB_DEVICE_ID_NCR_FIRST &&
@@ -1002,221 +290,3 @@ u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct)
}
EXPORT_SYMBOL_GPL(usbhid_lookup_quirk);
-
-/*
- * Cherry Cymotion keyboard have an invalid HID report descriptor,
- * that needs fixing before we can parse it.
- */
-static void usbhid_fixup_cymotion_descriptor(char *rdesc, int rsize)
-{
- if (rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
- printk(KERN_INFO "Fixing up Cherry Cymotion report descriptor\n");
- rdesc[11] = rdesc[16] = 0xff;
- rdesc[12] = rdesc[17] = 0x03;
- }
-}
-
-
-/*
- * Certain Logitech keyboards send in report #3 keys which are far
- * above the logical maximum described in descriptor. This extends
- * the original value of 0x28c of logical maximum to 0x104d
- */
-static void usbhid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 90 && rdesc[83] == 0x26
- && rdesc[84] == 0x8c
- && rdesc[85] == 0x02) {
- printk(KERN_INFO "Fixing up Logitech keyboard report descriptor\n");
- rdesc[84] = rdesc[89] = 0x4d;
- rdesc[85] = rdesc[90] = 0x10;
- }
-}
-
-static void usbhid_fixup_sunplus_wdesktop(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 107 && rdesc[104] == 0x26
- && rdesc[105] == 0x80
- && rdesc[106] == 0x03) {
- printk(KERN_INFO "Fixing up Sunplus Wireless Desktop report descriptor\n");
- rdesc[105] = rdesc[110] = 0x03;
- rdesc[106] = rdesc[111] = 0x21;
- }
-}
-
-/*
- * Samsung IrDA remote controller (reports as Cypress USB Mouse).
- *
- * Vendor specific report #4 has a size of 48 bit,
- * and therefore is not accepted when inspecting the descriptors.
- * As a workaround we reinterpret the report as:
- * Variable type, count 6, size 8 bit, log. maximum 255
- * The burden to reconstruct the data is moved into user space.
- */
-static void usbhid_fixup_samsung_irda_descriptor(unsigned char *rdesc,
- int rsize)
-{
- if (rsize >= 182 && rdesc[175] == 0x25
- && rdesc[176] == 0x40
- && rdesc[177] == 0x75
- && rdesc[178] == 0x30
- && rdesc[179] == 0x95
- && rdesc[180] == 0x01
- && rdesc[182] == 0x40) {
- printk(KERN_INFO "Fixing up Samsung IrDA report descriptor\n");
- rdesc[176] = 0xff;
- rdesc[178] = 0x08;
- rdesc[180] = 0x06;
- rdesc[182] = 0x42;
- }
-}
-
-/* Petalynx Maxter Remote has maximum for consumer page set too low */
-static void usbhid_fixup_petalynx_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 60 && rdesc[39] == 0x2a
- && rdesc[40] == 0xf5
- && rdesc[41] == 0x00
- && rdesc[59] == 0x26
- && rdesc[60] == 0xf9
- && rdesc[61] == 0x00) {
- printk(KERN_INFO "Fixing up Petalynx Maxter Remote report descriptor\n");
- rdesc[60] = 0xfa;
- rdesc[40] = 0xfa;
- }
-}
-
-/*
- * Some USB barcode readers from cypress have usage min and usage max in
- * the wrong order
- */
-static void usbhid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
-{
- short fixed = 0;
- int i;
-
- for (i = 0; i < rsize - 4; i++) {
- if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
- unsigned char tmp;
-
- rdesc[i] = 0x19; rdesc[i+2] = 0x29;
- tmp = rdesc[i+3];
- rdesc[i+3] = rdesc[i+1];
- rdesc[i+1] = tmp;
- }
- }
-
- if (fixed)
- printk(KERN_INFO "Fixing up Cypress report descriptor\n");
-}
-
-/*
- * MacBook JIS keyboard has wrong logical maximum
- */
-static void usbhid_fixup_macbook_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 60 && rdesc[53] == 0x65
- && rdesc[59] == 0x65) {
- printk(KERN_INFO "Fixing up MacBook JIS keyboard report descriptor\n");
- rdesc[53] = rdesc[59] = 0xe7;
- }
-}
-
-static void usbhid_fixup_button_consumer_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize >= 30 && rdesc[29] == 0x05
- && rdesc[30] == 0x09) {
- printk(KERN_INFO "Fixing up button/consumer in HID report descriptor\n");
- rdesc[30] = 0x0c;
- }
-}
-
-/*
- * Microsoft Wireless Desktop Receiver (Model 1028) has several
- * 'Usage Min/Max' where it ought to have 'Physical Min/Max'
- */
-static void usbhid_fixup_microsoft_descriptor(unsigned char *rdesc, int rsize)
-{
- if (rsize == 571 && rdesc[284] == 0x19
- && rdesc[286] == 0x2a
- && rdesc[304] == 0x19
- && rdesc[306] == 0x29
- && rdesc[352] == 0x1a
- && rdesc[355] == 0x2a
- && rdesc[557] == 0x19
- && rdesc[559] == 0x29) {
- printk(KERN_INFO "Fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
- rdesc[284] = rdesc[304] = rdesc[557] = 0x35;
- rdesc[352] = 0x36;
- rdesc[286] = rdesc[355] = 0x46;
- rdesc[306] = rdesc[559] = 0x45;
- }
-}
-
-static void __usbhid_fixup_report_descriptor(__u32 quirks, char *rdesc, unsigned rsize)
-{
- if ((quirks & HID_QUIRK_RDESC_CYMOTION))
- usbhid_fixup_cymotion_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_LOGITECH)
- usbhid_fixup_logitech_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_SWAPPED_MIN_MAX)
- usbhid_fixup_cypress_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_PETALYNX)
- usbhid_fixup_petalynx_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_MACBOOK_JIS)
- usbhid_fixup_macbook_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_BUTTON_CONSUMER)
- usbhid_fixup_button_consumer_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_SAMSUNG_REMOTE)
- usbhid_fixup_samsung_irda_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_MICROSOFT_RECV_1028)
- usbhid_fixup_microsoft_descriptor(rdesc, rsize);
-
- if (quirks & HID_QUIRK_RDESC_SUNPLUS_WDESKTOP)
- usbhid_fixup_sunplus_wdesktop(rdesc, rsize);
-}
-
-/**
- * usbhid_fixup_report_descriptor: check if report descriptor needs fixup
- *
- * Description:
- * Walks the hid_rdesc_blacklist[] array and checks whether the device
- * is known to have broken report descriptor that needs to be fixed up
- * prior to entering the HID parser
- *
- * Returns: nothing
- */
-void usbhid_fixup_report_descriptor(const u16 idVendor, const u16 idProduct,
- char *rdesc, unsigned rsize, char **quirks_param)
-{
- int n, m;
- u16 paramVendor, paramProduct;
- u32 quirks;
-
- /* static rdesc quirk entries */
- for (n = 0; hid_rdesc_blacklist[n].idVendor; n++)
- if (hid_rdesc_blacklist[n].idVendor == idVendor &&
- hid_rdesc_blacklist[n].idProduct == idProduct)
- __usbhid_fixup_report_descriptor(hid_rdesc_blacklist[n].quirks,
- rdesc, rsize);
-
- /* runtime rdesc quirk entries handling */
- for (n = 0; quirks_param[n] && n < MAX_USBHID_BOOT_QUIRKS; n++) {
- m = sscanf(quirks_param[n], "0x%hx:0x%hx:0x%x",
- &paramVendor, &paramProduct, &quirks);
-
- if (m != 3)
- printk(KERN_WARNING
- "Could not parse HID quirk module param %s\n",
- quirks_param[n]);
- else if (paramVendor == idVendor && paramProduct == idProduct)
- __usbhid_fixup_report_descriptor(quirks, rdesc, rsize);
- }
-}
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 842e9edb888..babd65dd46a 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -790,21 +790,23 @@ static struct usb_class_driver hiddev_class = {
/*
* This is where hid.c calls us to connect a hid device to the hiddev driver
*/
-int hiddev_connect(struct hid_device *hid)
+int hiddev_connect(struct hid_device *hid, unsigned int force)
{
struct hiddev *hiddev;
struct usbhid_device *usbhid = hid->driver_data;
- int i;
int retval;
- for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type ==
- HID_COLLECTION_APPLICATION &&
- !IS_INPUT_APPLICATION(hid->collection[i].usage))
- break;
+ if (!force) {
+ unsigned int i;
+ for (i = 0; i < hid->maxcollection; i++)
+ if (hid->collection[i].type ==
+ HID_COLLECTION_APPLICATION &&
+ !IS_INPUT_APPLICATION(hid->collection[i].usage))
+ break;
- if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
- return -1;
+ if (i == hid->maxcollection)
+ return -1;
+ }
if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 62d2d7c925b..abedb13c623 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -67,7 +67,7 @@ struct usbhid_device {
spinlock_t ctrllock; /* Control fifo spinlock */
struct urb *urbout; /* Output URB */
- struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
+ struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */
unsigned char outhead, outtail; /* Output pipe fifo head & tail */
char *outbuf; /* Output buffer */
dma_addr_t outbuf_dma; /* Output buffer dma */
@@ -82,7 +82,7 @@ struct usbhid_device {
};
#define hid_to_usb_dev(hid_dev) \
- container_of(hid_dev->dev->parent, struct usb_device, dev)
+ container_of(hid_dev->dev.parent->parent, struct usb_device, dev)
#endif
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index 0caaafe0184..b342926dd7f 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -105,14 +105,16 @@ static void usb_kbd_irq(struct urb *urb)
if (usb_kbd_keycode[kbd->old[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
else
- info("Unknown key (scancode %#x) released.", kbd->old[i]);
+ dev_info(&urb->dev->dev,
+ "Unknown key (scancode %#x) released.\n", kbd->old[i]);
}
if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
if (usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
else
- info("Unknown key (scancode %#x) pressed.", kbd->new[i]);
+ dev_info(&urb->dev->dev,
+ "Unknown key (scancode %#x) released.\n", kbd->new[i]);
}
}
@@ -159,7 +161,8 @@ static void usb_kbd_led(struct urb *urb)
struct usb_kbd *kbd = urb->context;
if (urb->status)
- warn("led urb status %d received", urb->status);
+ dev_warn(&urb->dev->dev, "led urb status %d received\n",
+ urb->status);
if (*(kbd->leds) == kbd->newleds)
return;
@@ -352,7 +355,8 @@ static int __init usb_kbd_init(void)
{
int result = usb_register(&usb_kbd_driver);
if (result == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return result;
}
diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c
index 35689ef172c..72ab4b26809 100644
--- a/drivers/hid/usbhid/usbmouse.c
+++ b/drivers/hid/usbhid/usbmouse.c
@@ -31,6 +31,11 @@
#include <linux/usb/input.h>
#include <linux/hid.h>
+/* for apple IDs */
+#ifdef CONFIG_USB_HID_MODULE
+#include "../hid-ids.h"
+#endif
+
/*
* Version Information
*/
@@ -240,7 +245,8 @@ static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver);
if (retval == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return retval;
}
diff --git a/drivers/hwmon/ams/ams.h b/drivers/hwmon/ams/ams.h
index a6221e5dd98..221ef6915a5 100644
--- a/drivers/hwmon/ams/ams.h
+++ b/drivers/hwmon/ams/ams.h
@@ -4,7 +4,7 @@
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include <linux/types.h>
-#include <asm/of_device.h>
+#include <linux/of_device.h>
enum ams_irq {
AMS_IRQ_FREEFALL = 0x01,
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index cdb8311e4ef..27a5d397f9a 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -175,11 +175,11 @@ static const u8 DME1737_BIT_ALARM_FAN[] = {10, 11, 12, 13, 22, 23};
* Data structures and manipulation thereof
* --------------------------------------------------------------------- */
-/* For ISA chips, we abuse the i2c_client addr and name fields. We also use
- the driver field to differentiate between I2C and ISA chips. */
struct dme1737_data {
- struct i2c_client client;
+ struct i2c_client *client; /* for I2C devices only */
struct device *hwmon_dev;
+ const char *name;
+ unsigned int addr; /* for ISA devices only */
struct mutex update_lock;
int valid; /* !=0 if following fields are valid */
@@ -512,11 +512,12 @@ static inline int PWM_OFF_TO_REG(int val, int ix, int reg)
* before calling dme1737_read or dme1737_write.
* --------------------------------------------------------------------- */
-static u8 dme1737_read(struct i2c_client *client, u8 reg)
+static u8 dme1737_read(const struct dme1737_data *data, u8 reg)
{
+ struct i2c_client *client = data->client;
s32 val;
- if (client->driver) { /* I2C device */
+ if (client) { /* I2C device */
val = i2c_smbus_read_byte_data(client, reg);
if (val < 0) {
@@ -525,18 +526,19 @@ static u8 dme1737_read(struct i2c_client *client, u8 reg)
"maintainer.\n", reg);
}
} else { /* ISA device */
- outb(reg, client->addr);
- val = inb(client->addr + 1);
+ outb(reg, data->addr);
+ val = inb(data->addr + 1);
}
return val;
}
-static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
+static s32 dme1737_write(const struct dme1737_data *data, u8 reg, u8 val)
{
+ struct i2c_client *client = data->client;
s32 res = 0;
- if (client->driver) { /* I2C device */
+ if (client) { /* I2C device */
res = i2c_smbus_write_byte_data(client, reg, val);
if (res < 0) {
@@ -545,8 +547,8 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
"maintainer.\n", reg);
}
} else { /* ISA device */
- outb(reg, client->addr);
- outb(val, client->addr + 1);
+ outb(reg, data->addr);
+ outb(val, data->addr + 1);
}
return res;
@@ -555,7 +557,6 @@ static s32 dme1737_write(struct i2c_client *client, u8 reg, u8 val)
static struct dme1737_data *dme1737_update_device(struct device *dev)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
int ix;
u8 lsb[5];
@@ -563,7 +564,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Enable a Vbat monitoring cycle every 10 mins */
if (time_after(jiffies, data->last_vbat + 600 * HZ) || !data->valid) {
- dme1737_write(client, DME1737_REG_CONFIG, dme1737_read(client,
+ dme1737_write(data, DME1737_REG_CONFIG, dme1737_read(data,
DME1737_REG_CONFIG) | 0x10);
data->last_vbat = jiffies;
}
@@ -571,7 +572,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Sample register contents every 1 sec */
if (time_after(jiffies, data->last_update + HZ) || !data->valid) {
if (data->type != sch5027) {
- data->vid = dme1737_read(client, DME1737_REG_VID) &
+ data->vid = dme1737_read(data, DME1737_REG_VID) &
0x3f;
}
@@ -580,11 +581,11 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
/* Voltage inputs are stored as 16 bit values even
* though they have only 12 bits resolution. This is
* to make it consistent with the temp inputs. */
- data->in[ix] = dme1737_read(client,
+ data->in[ix] = dme1737_read(data,
DME1737_REG_IN(ix)) << 8;
- data->in_min[ix] = dme1737_read(client,
+ data->in_min[ix] = dme1737_read(data,
DME1737_REG_IN_MIN(ix));
- data->in_max[ix] = dme1737_read(client,
+ data->in_max[ix] = dme1737_read(data,
DME1737_REG_IN_MAX(ix));
}
@@ -595,14 +596,14 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
* to take advantage of implicit conversions between
* register values (2's complement) and temp values
* (signed decimal). */
- data->temp[ix] = dme1737_read(client,
+ data->temp[ix] = dme1737_read(data,
DME1737_REG_TEMP(ix)) << 8;
- data->temp_min[ix] = dme1737_read(client,
+ data->temp_min[ix] = dme1737_read(data,
DME1737_REG_TEMP_MIN(ix));
- data->temp_max[ix] = dme1737_read(client,
+ data->temp_max[ix] = dme1737_read(data,
DME1737_REG_TEMP_MAX(ix));
if (data->type != sch5027) {
- data->temp_offset[ix] = dme1737_read(client,
+ data->temp_offset[ix] = dme1737_read(data,
DME1737_REG_TEMP_OFFSET(ix));
}
}
@@ -612,7 +613,7 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
* which the registers are read (MSB first, then LSB) is
* important! */
for (ix = 0; ix < ARRAY_SIZE(lsb); ix++) {
- lsb[ix] = dme1737_read(client,
+ lsb[ix] = dme1737_read(data,
DME1737_REG_IN_TEMP_LSB(ix));
}
for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
@@ -631,19 +632,19 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
if (!(data->has_fan & (1 << ix))) {
continue;
}
- data->fan[ix] = dme1737_read(client,
+ data->fan[ix] = dme1737_read(data,
DME1737_REG_FAN(ix));
- data->fan[ix] |= dme1737_read(client,
+ data->fan[ix] |= dme1737_read(data,
DME1737_REG_FAN(ix) + 1) << 8;
- data->fan_min[ix] = dme1737_read(client,
+ data->fan_min[ix] = dme1737_read(data,
DME1737_REG_FAN_MIN(ix));
- data->fan_min[ix] |= dme1737_read(client,
+ data->fan_min[ix] |= dme1737_read(data,
DME1737_REG_FAN_MIN(ix) + 1) << 8;
- data->fan_opt[ix] = dme1737_read(client,
+ data->fan_opt[ix] = dme1737_read(data,
DME1737_REG_FAN_OPT(ix));
/* fan_max exists only for fan[5-6] */
if (ix > 3) {
- data->fan_max[ix - 4] = dme1737_read(client,
+ data->fan_max[ix - 4] = dme1737_read(data,
DME1737_REG_FAN_MAX(ix));
}
}
@@ -655,63 +656,63 @@ static struct dme1737_data *dme1737_update_device(struct device *dev)
if (!(data->has_pwm & (1 << ix))) {
continue;
}
- data->pwm[ix] = dme1737_read(client,
+ data->pwm[ix] = dme1737_read(data,
DME1737_REG_PWM(ix));
- data->pwm_freq[ix] = dme1737_read(client,
+ data->pwm_freq[ix] = dme1737_read(data,
DME1737_REG_PWM_FREQ(ix));
/* pwm_config and pwm_min exist only for pwm[1-3] */
if (ix < 3) {
- data->pwm_config[ix] = dme1737_read(client,
+ data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix));
- data->pwm_min[ix] = dme1737_read(client,
+ data->pwm_min[ix] = dme1737_read(data,
DME1737_REG_PWM_MIN(ix));
}
}
for (ix = 0; ix < ARRAY_SIZE(data->pwm_rr); ix++) {
- data->pwm_rr[ix] = dme1737_read(client,
+ data->pwm_rr[ix] = dme1737_read(data,
DME1737_REG_PWM_RR(ix));
}
/* Thermal zone registers */
for (ix = 0; ix < ARRAY_SIZE(data->zone_low); ix++) {
- data->zone_low[ix] = dme1737_read(client,
+ data->zone_low[ix] = dme1737_read(data,
DME1737_REG_ZONE_LOW(ix));
- data->zone_abs[ix] = dme1737_read(client,
+ data->zone_abs[ix] = dme1737_read(data,
DME1737_REG_ZONE_ABS(ix));
}
if (data->type != sch5027) {
for (ix = 0; ix < ARRAY_SIZE(data->zone_hyst); ix++) {
- data->zone_hyst[ix] = dme1737_read(client,
+ data->zone_hyst[ix] = dme1737_read(data,
DME1737_REG_ZONE_HYST(ix));
}
}
/* Alarm registers */
- data->alarms = dme1737_read(client,
+ data->alarms = dme1737_read(data,
DME1737_REG_ALARM1);
/* Bit 7 tells us if the other alarm registers are non-zero and
* therefore also need to be read */
if (data->alarms & 0x80) {
- data->alarms |= dme1737_read(client,
+ data->alarms |= dme1737_read(data,
DME1737_REG_ALARM2) << 8;
- data->alarms |= dme1737_read(client,
+ data->alarms |= dme1737_read(data,
DME1737_REG_ALARM3) << 16;
}
/* The ISA chips require explicit clearing of alarm bits.
* Don't worry, an alarm will come back if the condition
* that causes it still exists */
- if (!client->driver) {
+ if (!data->client) {
if (data->alarms & 0xff0000) {
- dme1737_write(client, DME1737_REG_ALARM3,
+ dme1737_write(data, DME1737_REG_ALARM3,
0xff);
}
if (data->alarms & 0xff00) {
- dme1737_write(client, DME1737_REG_ALARM2,
+ dme1737_write(data, DME1737_REG_ALARM2,
0xff);
}
if (data->alarms & 0xff) {
- dme1737_write(client, DME1737_REG_ALARM1,
+ dme1737_write(data, DME1737_REG_ALARM1,
0xff);
}
}
@@ -770,7 +771,6 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -781,12 +781,12 @@ static ssize_t set_in(struct device *dev, struct device_attribute *attr,
switch (fn) {
case SYS_IN_MIN:
data->in_min[ix] = IN_TO_REG(val, data->in_nominal[ix]);
- dme1737_write(client, DME1737_REG_IN_MIN(ix),
+ dme1737_write(data, DME1737_REG_IN_MIN(ix),
data->in_min[ix]);
break;
case SYS_IN_MAX:
data->in_max[ix] = IN_TO_REG(val, data->in_nominal[ix]);
- dme1737_write(client, DME1737_REG_IN_MAX(ix),
+ dme1737_write(data, DME1737_REG_IN_MAX(ix),
data->in_max[ix]);
break;
default:
@@ -850,7 +850,6 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -861,17 +860,17 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
switch (fn) {
case SYS_TEMP_MIN:
data->temp_min[ix] = TEMP_TO_REG(val);
- dme1737_write(client, DME1737_REG_TEMP_MIN(ix),
+ dme1737_write(data, DME1737_REG_TEMP_MIN(ix),
data->temp_min[ix]);
break;
case SYS_TEMP_MAX:
data->temp_max[ix] = TEMP_TO_REG(val);
- dme1737_write(client, DME1737_REG_TEMP_MAX(ix),
+ dme1737_write(data, DME1737_REG_TEMP_MAX(ix),
data->temp_max[ix]);
break;
case SYS_TEMP_OFFSET:
data->temp_offset[ix] = TEMP_TO_REG(val);
- dme1737_write(client, DME1737_REG_TEMP_OFFSET(ix),
+ dme1737_write(data, DME1737_REG_TEMP_OFFSET(ix),
data->temp_offset[ix]);
break;
default:
@@ -939,7 +938,6 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -950,37 +948,37 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr,
switch (fn) {
case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
/* Refresh the cache */
- data->zone_low[ix] = dme1737_read(client,
+ data->zone_low[ix] = dme1737_read(data,
DME1737_REG_ZONE_LOW(ix));
/* Modify the temp hyst value */
data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(
TEMP_FROM_REG(data->zone_low[ix], 8) -
- val, ix, dme1737_read(client,
+ val, ix, dme1737_read(data,
DME1737_REG_ZONE_HYST(ix == 2)));
- dme1737_write(client, DME1737_REG_ZONE_HYST(ix == 2),
+ dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2),
data->zone_hyst[ix == 2]);
break;
case SYS_ZONE_AUTO_POINT1_TEMP:
data->zone_low[ix] = TEMP_TO_REG(val);
- dme1737_write(client, DME1737_REG_ZONE_LOW(ix),
+ dme1737_write(data, DME1737_REG_ZONE_LOW(ix),
data->zone_low[ix]);
break;
case SYS_ZONE_AUTO_POINT2_TEMP:
/* Refresh the cache */
- data->zone_low[ix] = dme1737_read(client,
+ data->zone_low[ix] = dme1737_read(data,
DME1737_REG_ZONE_LOW(ix));
/* Modify the temp range value (which is stored in the upper
* nibble of the pwm_freq register) */
data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val -
TEMP_FROM_REG(data->zone_low[ix], 8),
- dme1737_read(client,
+ dme1737_read(data,
DME1737_REG_PWM_FREQ(ix)));
- dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
data->pwm_freq[ix]);
break;
case SYS_ZONE_AUTO_POINT3_TEMP:
data->zone_abs[ix] = TEMP_TO_REG(val);
- dme1737_write(client, DME1737_REG_ZONE_ABS(ix),
+ dme1737_write(data, DME1737_REG_ZONE_ABS(ix),
data->zone_abs[ix]);
break;
default:
@@ -1046,7 +1044,6 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -1060,21 +1057,21 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
data->fan_min[ix] = FAN_TO_REG(val, 0);
} else {
/* Refresh the cache */
- data->fan_opt[ix] = dme1737_read(client,
+ data->fan_opt[ix] = dme1737_read(data,
DME1737_REG_FAN_OPT(ix));
/* Modify the fan min value */
data->fan_min[ix] = FAN_TO_REG(val,
FAN_TPC_FROM_REG(data->fan_opt[ix]));
}
- dme1737_write(client, DME1737_REG_FAN_MIN(ix),
+ dme1737_write(data, DME1737_REG_FAN_MIN(ix),
data->fan_min[ix] & 0xff);
- dme1737_write(client, DME1737_REG_FAN_MIN(ix) + 1,
+ dme1737_write(data, DME1737_REG_FAN_MIN(ix) + 1,
data->fan_min[ix] >> 8);
break;
case SYS_FAN_MAX:
/* Only valid for fan[5-6] */
data->fan_max[ix - 4] = FAN_MAX_TO_REG(val);
- dme1737_write(client, DME1737_REG_FAN_MAX(ix),
+ dme1737_write(data, DME1737_REG_FAN_MAX(ix),
data->fan_max[ix - 4]);
break;
case SYS_FAN_TYPE:
@@ -1086,9 +1083,9 @@ static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
val);
goto exit;
}
- data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(client,
+ data->fan_opt[ix] = FAN_TYPE_TO_REG(val, dme1737_read(data,
DME1737_REG_FAN_OPT(ix)));
- dme1737_write(client, DME1737_REG_FAN_OPT(ix),
+ dme1737_write(data, DME1737_REG_FAN_OPT(ix),
data->fan_opt[ix]);
break;
default:
@@ -1185,7 +1182,6 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
struct sensor_device_attribute_2
*sensor_attr_2 = to_sensor_dev_attr_2(attr);
int ix = sensor_attr_2->index;
@@ -1196,12 +1192,12 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
switch (fn) {
case SYS_PWM:
data->pwm[ix] = SENSORS_LIMIT(val, 0, 255);
- dme1737_write(client, DME1737_REG_PWM(ix), data->pwm[ix]);
+ dme1737_write(data, DME1737_REG_PWM(ix), data->pwm[ix]);
break;
case SYS_PWM_FREQ:
- data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(client,
+ data->pwm_freq[ix] = PWM_FREQ_TO_REG(val, dme1737_read(data,
DME1737_REG_PWM_FREQ(ix)));
- dme1737_write(client, DME1737_REG_PWM_FREQ(ix),
+ dme1737_write(data, DME1737_REG_PWM_FREQ(ix),
data->pwm_freq[ix]);
break;
case SYS_PWM_ENABLE:
@@ -1214,7 +1210,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
goto exit;
}
/* Refresh the cache */
- data->pwm_config[ix] = dme1737_read(client,
+ data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix));
if (val == PWM_EN_FROM_REG(data->pwm_config[ix])) {
/* Bail out if no change */
@@ -1226,14 +1222,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_acz[ix] = PWM_ACZ_FROM_REG(
data->pwm_config[ix]);
/* Save the current ramp rate state and disable it */
- data->pwm_rr[ix > 0] = dme1737_read(client,
+ data->pwm_rr[ix > 0] = dme1737_read(data,
DME1737_REG_PWM_RR(ix > 0));
data->pwm_rr_en &= ~(1 << ix);
if (PWM_RR_EN_FROM_REG(data->pwm_rr[ix > 0], ix)) {
data->pwm_rr_en |= (1 << ix);
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(0, ix,
data->pwm_rr[ix > 0]);
- dme1737_write(client,
+ dme1737_write(data,
DME1737_REG_PWM_RR(ix > 0),
data->pwm_rr[ix > 0]);
}
@@ -1247,14 +1243,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
/* Turn fan fully on */
data->pwm_config[ix] = PWM_EN_TO_REG(0,
data->pwm_config[ix]);
- dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
break;
case 1:
/* Turn on manual mode */
data->pwm_config[ix] = PWM_EN_TO_REG(1,
data->pwm_config[ix]);
- dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
/* Change permissions of pwm[ix] to read-writeable */
dme1737_chmod_file(dev, dme1737_pwm_chmod_attr[ix],
@@ -1269,14 +1265,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_config[ix] = PWM_ACZ_TO_REG(
data->pwm_acz[ix],
data->pwm_config[ix]);
- dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
/* Enable PWM ramp rate if previously enabled */
if (data->pwm_rr_en & (1 << ix)) {
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(1, ix,
- dme1737_read(client,
+ dme1737_read(data,
DME1737_REG_PWM_RR(ix > 0)));
- dme1737_write(client,
+ dme1737_write(data,
DME1737_REG_PWM_RR(ix > 0),
data->pwm_rr[ix > 0]);
}
@@ -1286,9 +1282,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
case SYS_PWM_RAMP_RATE:
/* Only valid for pwm[1-3] */
/* Refresh the cache */
- data->pwm_config[ix] = dme1737_read(client,
+ data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix));
- data->pwm_rr[ix > 0] = dme1737_read(client,
+ data->pwm_rr[ix > 0] = dme1737_read(data,
DME1737_REG_PWM_RR(ix > 0));
/* Set the ramp rate value */
if (val > 0) {
@@ -1301,7 +1297,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
data->pwm_rr[ix > 0] = PWM_RR_EN_TO_REG(val > 0, ix,
data->pwm_rr[ix > 0]);
}
- dme1737_write(client, DME1737_REG_PWM_RR(ix > 0),
+ dme1737_write(data, DME1737_REG_PWM_RR(ix > 0),
data->pwm_rr[ix > 0]);
break;
case SYS_PWM_AUTO_CHANNELS_ZONE:
@@ -1315,14 +1311,14 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
goto exit;
}
/* Refresh the cache */
- data->pwm_config[ix] = dme1737_read(client,
+ data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix));
if (PWM_EN_FROM_REG(data->pwm_config[ix]) == 2) {
/* PWM is already in auto mode so update the temp
* channel assignment */
data->pwm_config[ix] = PWM_ACZ_TO_REG(val,
data->pwm_config[ix]);
- dme1737_write(client, DME1737_REG_PWM_CONFIG(ix),
+ dme1737_write(data, DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
} else {
/* PWM is not in auto mode so we save the temp
@@ -1333,7 +1329,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
case SYS_PWM_AUTO_PWM_MIN:
/* Only valid for pwm[1-3] */
/* Refresh the cache */
- data->pwm_min[ix] = dme1737_read(client,
+ data->pwm_min[ix] = dme1737_read(data,
DME1737_REG_PWM_MIN(ix));
/* There are only 2 values supported for the auto_pwm_min
* value: 0 or auto_point1_pwm. So if the temperature drops
@@ -1341,20 +1337,20 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
* off or runs at auto_point1_pwm duty-cycle. */
if (val > ((data->pwm_min[ix] + 1) / 2)) {
data->pwm_rr[0] = PWM_OFF_TO_REG(1, ix,
- dme1737_read(client,
+ dme1737_read(data,
DME1737_REG_PWM_RR(0)));
} else {
data->pwm_rr[0] = PWM_OFF_TO_REG(0, ix,
- dme1737_read(client,
+ dme1737_read(data,
DME1737_REG_PWM_RR(0)));
}
- dme1737_write(client, DME1737_REG_PWM_RR(0),
+ dme1737_write(data, DME1737_REG_PWM_RR(0),
data->pwm_rr[0]);
break;
case SYS_PWM_AUTO_POINT1_PWM:
/* Only valid for pwm[1-3] */
data->pwm_min[ix] = SENSORS_LIMIT(val, 0, 255);
- dme1737_write(client, DME1737_REG_PWM_MIN(ix),
+ dme1737_write(data, DME1737_REG_PWM_MIN(ix),
data->pwm_min[ix]);
break;
default:
@@ -1402,7 +1398,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr,
{
struct dme1737_data *data = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", data->client.name);
+ return sprintf(buf, "%s\n", data->name);
}
/* ---------------------------------------------------------------------
@@ -1908,7 +1904,7 @@ static void dme1737_remove_files(struct device *dev)
sysfs_remove_group(&dev->kobj, &dme1737_group);
- if (!data->client.driver) {
+ if (!data->client) {
sysfs_remove_file(&dev->kobj, &dev_attr_name.attr);
}
}
@@ -1919,7 +1915,7 @@ static int dme1737_create_files(struct device *dev)
int err, ix;
/* Create a name attribute for ISA devices */
- if (!data->client.driver &&
+ if (!data->client &&
(err = sysfs_create_file(&dev->kobj, &dev_attr_name.attr))) {
goto exit;
}
@@ -2013,14 +2009,14 @@ exit:
static int dme1737_init_device(struct device *dev)
{
struct dme1737_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = &data->client;
+ struct i2c_client *client = data->client;
int ix;
u8 reg;
/* Point to the right nominal voltages array */
data->in_nominal = IN_NOMINAL(data->type);
- data->config = dme1737_read(client, DME1737_REG_CONFIG);
+ data->config = dme1737_read(data, DME1737_REG_CONFIG);
/* Inform if part is not monitoring/started */
if (!(data->config & 0x01)) {
if (!force_start) {
@@ -2032,7 +2028,7 @@ static int dme1737_init_device(struct device *dev)
/* Force monitoring */
data->config |= 0x01;
- dme1737_write(client, DME1737_REG_CONFIG, data->config);
+ dme1737_write(data, DME1737_REG_CONFIG, data->config);
}
/* Inform if part is not ready */
if (!(data->config & 0x04)) {
@@ -2041,8 +2037,8 @@ static int dme1737_init_device(struct device *dev)
}
/* Determine which optional fan and pwm features are enabled/present */
- if (client->driver) { /* I2C chip */
- data->config2 = dme1737_read(client, DME1737_REG_CONFIG2);
+ if (client) { /* I2C chip */
+ data->config2 = dme1737_read(data, DME1737_REG_CONFIG2);
/* Check if optional fan3 input is enabled */
if (data->config2 & 0x04) {
data->has_fan |= (1 << 2);
@@ -2051,7 +2047,7 @@ static int dme1737_init_device(struct device *dev)
/* Fan4 and pwm3 are only available if the client's I2C address
* is the default 0x2e. Otherwise the I/Os associated with
* these functions are used for addr enable/select. */
- if (data->client.addr == 0x2e) {
+ if (client->addr == 0x2e) {
data->has_fan |= (1 << 3);
data->has_pwm |= (1 << 2);
}
@@ -2086,16 +2082,16 @@ static int dme1737_init_device(struct device *dev)
(data->has_fan & (1 << 4)) ? "yes" : "no",
(data->has_fan & (1 << 5)) ? "yes" : "no");
- reg = dme1737_read(client, DME1737_REG_TACH_PWM);
+ reg = dme1737_read(data, DME1737_REG_TACH_PWM);
/* Inform if fan-to-pwm mapping differs from the default */
- if (client->driver && reg != 0xa4) { /* I2C chip */
+ if (client && reg != 0xa4) { /* I2C chip */
dev_warn(dev, "Non-standard fan to pwm mapping: "
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d, "
"fan4->pwm%d. Please report to the driver "
"maintainer.\n",
(reg & 0x03) + 1, ((reg >> 2) & 0x03) + 1,
((reg >> 4) & 0x03) + 1, ((reg >> 6) & 0x03) + 1);
- } else if (!client->driver && reg != 0x24) { /* ISA chip */
+ } else if (!client && reg != 0x24) { /* ISA chip */
dev_warn(dev, "Non-standard fan to pwm mapping: "
"fan1->pwm%d, fan2->pwm%d, fan3->pwm%d. "
"Please report to the driver maintainer.\n",
@@ -2108,7 +2104,7 @@ static int dme1737_init_device(struct device *dev)
* disabled). */
if (!(data->config & 0x02)) {
for (ix = 0; ix < 3; ix++) {
- data->pwm_config[ix] = dme1737_read(client,
+ data->pwm_config[ix] = dme1737_read(data,
DME1737_REG_PWM_CONFIG(ix));
if ((data->has_pwm & (1 << ix)) &&
(PWM_EN_FROM_REG(data->pwm_config[ix]) == -1)) {
@@ -2116,8 +2112,8 @@ static int dme1737_init_device(struct device *dev)
"manual mode.\n", ix + 1);
data->pwm_config[ix] = PWM_EN_TO_REG(1,
data->pwm_config[ix]);
- dme1737_write(client, DME1737_REG_PWM(ix), 0);
- dme1737_write(client,
+ dme1737_write(data, DME1737_REG_PWM(ix), 0);
+ dme1737_write(data,
DME1737_REG_PWM_CONFIG(ix),
data->pwm_config[ix]);
}
@@ -2191,37 +2187,24 @@ exit:
return err;
}
-static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
- int kind)
+/* Return 0 if detection is successful, -ENODEV otherwise */
+static int dme1737_i2c_detect(struct i2c_client *client, int kind,
+ struct i2c_board_info *info)
{
+ struct i2c_adapter *adapter = client->adapter;
+ struct device *dev = &adapter->dev;
u8 company, verstep = 0;
- struct i2c_client *client;
- struct dme1737_data *data;
- struct device *dev;
- int err = 0;
const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
- goto exit;
- }
-
- if (!(data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
+ return -ENODEV;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = address;
- client->adapter = adapter;
- client->driver = &dme1737_i2c_driver;
- dev = &client->dev;
-
/* A negative kind means that the driver was loaded with no force
* parameter (default), so we must identify the chip. */
if (kind < 0) {
- company = dme1737_read(client, DME1737_REG_COMPANY);
- verstep = dme1737_read(client, DME1737_REG_VERSTEP);
+ company = i2c_smbus_read_byte_data(client, DME1737_REG_COMPANY);
+ verstep = i2c_smbus_read_byte_data(client, DME1737_REG_VERSTEP);
if (company == DME1737_COMPANY_SMSC &&
(verstep & DME1737_VERSTEP_MASK) == DME1737_VERSTEP) {
@@ -2230,8 +2213,7 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
verstep == SCH5027_VERSTEP) {
kind = sch5027;
} else {
- err = -ENODEV;
- goto exit_kfree;
+ return -ENODEV;
}
}
@@ -2241,32 +2223,44 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
kind = dme1737;
name = "dme1737";
}
- data->type = kind;
-
- /* Fill in the remaining client fields and put it into the global
- * list */
- strlcpy(client->name, name, I2C_NAME_SIZE);
- mutex_init(&data->update_lock);
-
- /* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(client))) {
- goto exit_kfree;
- }
dev_info(dev, "Found a %s chip at 0x%02x (rev 0x%02x).\n",
kind == sch5027 ? "SCH5027" : "DME1737", client->addr,
verstep);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
+
+ return 0;
+}
+
+static int dme1737_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct dme1737_data *data;
+ struct device *dev = &client->dev;
+ int err;
+
+ data = kzalloc(sizeof(struct dme1737_data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ i2c_set_clientdata(client, data);
+ data->type = id->driver_data;
+ data->client = client;
+ data->name = client->name;
+ mutex_init(&data->update_lock);
/* Initialize the DME1737 chip */
if ((err = dme1737_init_device(dev))) {
dev_err(dev, "Failed to initialize device.\n");
- goto exit_detach;
+ goto exit_kfree;
}
/* Create sysfs files */
if ((err = dme1737_create_files(dev))) {
dev_err(dev, "Failed to create sysfs files.\n");
- goto exit_detach;
+ goto exit_kfree;
}
/* Register device */
@@ -2281,45 +2275,40 @@ static int dme1737_i2c_detect(struct i2c_adapter *adapter, int address,
exit_remove:
dme1737_remove_files(dev);
-exit_detach:
- i2c_detach_client(client);
exit_kfree:
kfree(data);
exit:
return err;
}
-static int dme1737_i2c_attach_adapter(struct i2c_adapter *adapter)
-{
- if (!(adapter->class & I2C_CLASS_HWMON)) {
- return 0;
- }
-
- return i2c_probe(adapter, &addr_data, dme1737_i2c_detect);
-}
-
-static int dme1737_i2c_detach_client(struct i2c_client *client)
+static int dme1737_i2c_remove(struct i2c_client *client)
{
struct dme1737_data *data = i2c_get_clientdata(client);
- int err;
hwmon_device_unregister(data->hwmon_dev);
dme1737_remove_files(&client->dev);
- if ((err = i2c_detach_client(client))) {
- return err;
- }
-
kfree(data);
return 0;
}
+static const struct i2c_device_id dme1737_id[] = {
+ { "dme1737", dme1737 },
+ { "sch5027", sch5027 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, dme1737_id);
+
static struct i2c_driver dme1737_i2c_driver = {
+ .class = I2C_CLASS_HWMON,
.driver = {
.name = "dme1737",
},
- .attach_adapter = dme1737_i2c_attach_adapter,
- .detach_client = dme1737_i2c_detach_client,
+ .probe = dme1737_i2c_probe,
+ .remove = dme1737_i2c_remove,
+ .id_table = dme1737_id,
+ .detect = dme1737_i2c_detect,
+ .address_data = &addr_data,
};
/* ---------------------------------------------------------------------
@@ -2403,7 +2392,6 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
{
u8 company, device;
struct resource *res;
- struct i2c_client *client;
struct dme1737_data *data;
struct device *dev = &pdev->dev;
int err;
@@ -2422,15 +2410,13 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
goto exit_release_region;
}
- client = &data->client;
- i2c_set_clientdata(client, data);
- client->addr = res->start;
+ data->addr = res->start;
platform_set_drvdata(pdev, data);
/* Skip chip detection if module is loaded with force_id parameter */
if (!force_id) {
- company = dme1737_read(client, DME1737_REG_COMPANY);
- device = dme1737_read(client, DME1737_REG_DEVICE);
+ company = dme1737_read(data, DME1737_REG_COMPANY);
+ device = dme1737_read(data, DME1737_REG_DEVICE);
if (!((company == DME1737_COMPANY_SMSC) &&
(device == SCH311X_DEVICE))) {
@@ -2441,10 +2427,10 @@ static int __devinit dme1737_isa_probe(struct platform_device *pdev)
data->type = sch311x;
/* Fill in the remaining client fields and initialize the mutex */
- strlcpy(client->name, "sch311x", I2C_NAME_SIZE);
+ data->name = "sch311x";
mutex_init(&data->update_lock);
- dev_info(dev, "Found a SCH311x chip at 0x%04x\n", client->addr);
+ dev_info(dev, "Found a SCH311x chip at 0x%04x\n", data->addr);
/* Initialize the chip */
if ((err = dme1737_init_device(dev))) {
@@ -2485,7 +2471,7 @@ static int __devexit dme1737_isa_remove(struct platform_device *pdev)
hwmon_device_unregister(data->hwmon_dev);
dme1737_remove_files(&pdev->dev);
- release_region(data->client.addr, DME1737_EXTENT);
+ release_region(data->addr, DME1737_EXTENT);
platform_set_drvdata(pdev, NULL);
kfree(data);
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 6ee997b2817..acadbc51fc0 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -55,7 +55,7 @@ config I2C_AMD756
config I2C_AMD756_S4882
tristate "SMBus multiplexing on the Tyan S4882"
- depends on I2C_AMD756 && EXPERIMENTAL
+ depends on I2C_AMD756 && X86 && EXPERIMENTAL
help
Enabling this option will add specific SMBus support for the Tyan
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -148,7 +148,7 @@ config I2C_NFORCE2
config I2C_NFORCE2_S4985
tristate "SMBus multiplexing on the Tyan S4985"
- depends on I2C_NFORCE2 && EXPERIMENTAL
+ depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
help
Enabling this option will add specific SMBus support for the Tyan
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -209,7 +209,7 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA VT82C596/82C686/82xx and CX700"
+ tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
depends on PCI
help
If you say yes to this option, support will be included for the VIA
@@ -223,6 +223,8 @@ config I2C_VIAPRO
VT8237R/A/S
VT8251
CX700
+ VX800
+ VX820
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
@@ -330,6 +332,18 @@ config I2C_GPIO
This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines.
+config I2C_HIGHLANDER
+ tristate "Highlander FPGA SMBus interface"
+ depends on SH_HIGHLANDER
+ help
+ If you say yes to this option, support will be included for
+ the SMBus interface located in the FPGA on various Highlander
+ boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+ FPGAs. This is wholly unrelated to the SoC I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-highlander.
+
config I2C_IBM_IIC
tristate "IBM PPC 4xx on-chip I2C interface"
depends on 4xx
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 97dbfa2107f..0c2c4b26cdf 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 00000000000..f4d22ae9d29
--- /dev/null
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,498 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008 Paul Mundt
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Copyright (C) 2008 Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define SMCR 0x00
+#define SMCR_START (1 << 0)
+#define SMCR_IRIC (1 << 1)
+#define SMCR_BBSY (1 << 2)
+#define SMCR_ACKE (1 << 3)
+#define SMCR_RST (1 << 4)
+#define SMCR_IEIC (1 << 6)
+
+#define SMSMADR 0x02
+
+#define SMMR 0x04
+#define SMMR_MODE0 (1 << 0)
+#define SMMR_MODE1 (1 << 1)
+#define SMMR_CAP (1 << 3)
+#define SMMR_TMMD (1 << 4)
+#define SMMR_SP (1 << 7)
+
+#define SMSADR 0x06
+#define SMTRDR 0x46
+
+struct highlander_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_adapter adapter;
+ struct completion cmd_complete;
+ unsigned long last_read_time;
+ int irq;
+ u8 *buf;
+ size_t buf_len;
+};
+
+static int iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+ u16 smmr;
+
+ smmr = ioread16(dev->base + SMMR);
+ smmr |= SMMR_TMMD;
+
+ if (iic_force_normal)
+ smmr &= ~SMMR_SP;
+ else
+ smmr |= SMMR_SP;
+
+ iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *dst++ = be16_to_cpup((u16 *)src);
+ src += 2;
+ }
+
+ if (len)
+ *dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *(u16 *)dst = cpu_to_be16p(src++);
+ dst += 2;
+ }
+
+ if (len)
+ *dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+ u8 command, int len)
+{
+ unsigned int i;
+ u16 cmd = (command << 8) | command;
+
+ for (i = 0; i < len; i += 2) {
+ if (len - i == 1)
+ cmd = command << 8;
+ iowrite16(cmd, dev->base + SMSADR + i);
+ dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+ }
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+ return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+ u16 tmp = ioread16(dev->base + SMCR);
+
+ if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+ dev_warn(dev->dev, "ack abnormality\n");
+ return highlander_i2c_reset(dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+ struct highlander_i2c_dev *dev = dev_id;
+
+ highlander_i2c_done(dev);
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+ u16 smcr;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ for (;;) {
+ smcr = ioread16(dev->base + SMCR);
+
+ /*
+ * Don't bother checking ACKE here, this and the reset
+ * are handled in highlander_i2c_wait_xfer_done() when
+ * waiting for the ACK.
+ */
+
+ if (smcr & SMCR_IRIC)
+ return;
+ if (time_after(jiffies, timeout))
+ break;
+
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+ if (dev->irq)
+ wait_for_completion_timeout(&dev->cmd_complete,
+ msecs_to_jiffies(iic_timeout));
+ else
+ /* busy looping, the IRQ of champions */
+ highlander_i2c_poll(dev);
+
+ return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ if (highlander_i2c_wait_xfer_done(dev)) {
+ dev_err(dev->dev, "Arbitration loss\n");
+ return -EAGAIN;
+ }
+
+ /*
+ * The R0P7780LC0011RL FPGA needs a significant delay between
+ * data read cycles, otherwise the transciever gets confused and
+ * garbage is returned when the read is subsequently aborted.
+ *
+ * It is not sufficient to wait for BBSY.
+ *
+ * While this generally only applies to the older SH7780-based
+ * Highlanders, the same issue can be observed on SH7785 ones,
+ * albeit less frequently. SH7780-based Highlanders may need
+ * this to be as high as 1000 ms.
+ */
+ if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)))
+ msleep(jiffies_to_msecs((dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ smbus_read_data(data, dev->buf, dev->buf_len);
+
+ dev->last_read_time = jiffies;
+
+ return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ smbus_write_data(dev->buf, data, dev->buf_len);
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+ int read = read_write & I2C_SMBUS_READ;
+ u16 tmp;
+
+ init_completion(&dev->cmd_complete);
+
+ dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+ addr, command, read_write, size);
+
+ /*
+ * Set up the buffer and transfer size
+ */
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ dev->buf = &data->byte;
+ dev->buf_len = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ dev->buf = &data->block[1];
+ dev->buf_len = data->block[0];
+ break;
+ default:
+ dev_err(dev->dev, "unsupported command %d\n", size);
+ return -EINVAL;
+ }
+
+ /*
+ * Encode the mode setting
+ */
+ tmp = ioread16(dev->base + SMMR);
+ tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+ switch (dev->buf_len) {
+ case 1:
+ /* default */
+ break;
+ case 8:
+ tmp |= SMMR_MODE0;
+ break;
+ case 16:
+ tmp |= SMMR_MODE1;
+ break;
+ case 32:
+ tmp |= (SMMR_MODE0 | SMMR_MODE1);
+ break;
+ default:
+ dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+ return -EINVAL;
+ }
+
+ iowrite16(tmp, dev->base + SMMR);
+
+ /* Ensure we're in a sane state */
+ highlander_i2c_done(dev);
+
+ /* Set slave address */
+ iowrite16((addr << 1) | read, dev->base + SMSMADR);
+
+ highlander_i2c_command(dev, command, dev->buf_len);
+
+ if (read)
+ return highlander_i2c_read(dev);
+ else
+ return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+ .smbus_xfer = highlander_i2c_smbus_xfer,
+ .functionality = highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+ if (unlikely(!dev))
+ return -ENOMEM;
+
+ dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (unlikely(!dev->base)) {
+ ret = -ENXIO;
+ goto err;
+ }
+
+ dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dev);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (iic_force_poll)
+ dev->irq = 0;
+
+ if (dev->irq) {
+ ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+ pdev->name, dev);
+ if (unlikely(ret))
+ goto err_unmap;
+
+ highlander_i2c_irq_enable(dev);
+ } else {
+ dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+ highlander_i2c_irq_disable(dev);
+ }
+
+ dev->last_read_time = jiffies; /* initial read jiffies */
+
+ highlander_i2c_setup(dev);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+ adap->algo = &highlander_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+
+ /*
+ * Reset the adapter
+ */
+ ret = highlander_i2c_reset(dev);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "controller didn't come up\n");
+ goto err_free_irq;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+err_unmap:
+ iounmap(dev->base);
+err:
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+ .driver = {
+ .name = "i2c-highlander",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = highlander_i2c_probe,
+ .remove = __devexit_p(highlander_i2c_remove),
+};
+
+static int __init highlander_i2c_init(void)
+{
+ return platform_driver_register(&highlander_i2c_driver);
+}
+
+static void __exit highlander_i2c_exit(void)
+{
+ platform_driver_unregister(&highlander_i2c_driver);
+}
+
+module_init(highlander_i2c_init);
+module_exit(highlander_i2c_exit);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+ "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+ "Delay between data read cycles (default 0 ms)");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 27443f073bc..a9a45fcc854 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -312,7 +312,6 @@ static struct i2c_adapter mpc_ops = {
.name = "MPC adapter",
.id = I2C_HW_MPC107,
.algo = &mpc_algo,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.timeout = 1,
};
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index c6faf9bdad1..b2b8380f660 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -123,11 +123,6 @@ static struct i2c_adapter parport_adapter = {
static int __devinit i2c_parport_probe(struct platform_device *pdev)
{
int err;
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
- return -EBUSY;
/* Reset hardware to a sane state (SCL and SDA high) */
parport_setsda(NULL, 1);
@@ -138,29 +133,19 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
parport_adapter.dev.parent = &pdev->dev;
err = i2c_bit_add_bus(&parport_adapter);
- if (err) {
+ if (err)
dev_err(&pdev->dev, "Unable to register with I2C\n");
- goto exit_region;
- }
- return 0;
-
-exit_region:
- release_region(res->start, res->end - res->start + 1);
return err;
}
static int __devexit i2c_parport_remove(struct platform_device *pdev)
{
- struct resource *res;
-
i2c_del_adapter(&parport_adapter);
/* Un-init if needed (power off...) */
if (adapter_parm[type].init.val)
line_set(0, &adapter_parm[type].init);
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, res->end - res->start + 1);
return 0;
}
@@ -175,12 +160,6 @@ static struct platform_driver i2c_parport_driver = {
static int __init i2c_parport_device_add(u16 address)
{
- struct resource res = {
- .start = address,
- .end = address + 2,
- .name = DRVNAME,
- .flags = IORESOURCE_IO,
- };
int err;
pdev = platform_device_alloc(DRVNAME, -1);
@@ -190,13 +169,6 @@ static int __init i2c_parport_device_add(u16 address)
goto exit;
}
- err = platform_device_add_resources(pdev, &res, 1);
- if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
- goto exit_device_put;
- }
-
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
@@ -231,13 +203,16 @@ static int __init i2c_parport_init(void)
base = DEFAULT_BASE;
}
+ if (!request_region(base, 3, DRVNAME))
+ return -EBUSY;
+
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
/* Sets global pdev as a side effect */
err = i2c_parport_device_add(base);
if (err)
- goto exit;
+ goto exit_release;
err = platform_driver_register(&i2c_parport_driver);
if (err)
@@ -247,7 +222,8 @@ static int __init i2c_parport_init(void)
exit_device:
platform_device_unregister(pdev);
-exit:
+exit_release:
+ release_region(base, 3);
return err;
}
@@ -255,6 +231,7 @@ static void __exit i2c_parport_exit(void)
{
platform_driver_unregister(&i2c_parport_driver);
platform_device_unregister(pdev);
+ release_region(base, 3);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index a119784bae1..9eb76268ec7 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -36,8 +36,8 @@
#define DRIVER "i2c-pca-isa"
#define IO_SIZE 4
-static unsigned long base = 0x330;
-static int irq = 10;
+static unsigned long base;
+static int irq = -1;
/* Data sheet recommends 59kHz for 100kHz operation due to variation
* in the actual clock rate */
@@ -107,13 +107,26 @@ static struct i2c_adapter pca_isa_ops = {
.timeout = 100,
};
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+ int match = base != 0;
+
+ if (match) {
+ if (irq <= -1)
+ dev_warn(dev, "Using polling mode (specify irq)\n");
+ } else
+ dev_err(dev, "Please specify I/O base\n");
+
+ return match;
+}
+
static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
{
init_waitqueue_head(&pca_wait);
dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (check_legacy_ioport(base)) {
dev_err(dev, "I/O address %#08lx is not available\n", base);
goto out;
@@ -153,7 +166,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pca_isa_ops);
- if (irq > 0) {
+ if (irq > -1) {
disable_irq(irq);
free_irq(irq, &pca_isa_ops);
}
@@ -163,6 +176,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
}
static struct isa_driver pca_isa_driver = {
+ .match = pca_isa_match,
.probe = pca_isa_probe,
.remove = __devexit_p(pca_isa_remove),
.driver = {
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 862eb352a2d..73dc52e114e 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -36,6 +36,7 @@
VT8237S 0x3372 yes
VT8251 0x3287 yes
CX700 0x8324 yes
+ VX800/VX820 0x8353 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -82,6 +83,7 @@ static unsigned short SMBHSTCFG = 0xD2;
#define VT596_BYTE 0x04
#define VT596_BYTE_DATA 0x08
#define VT596_WORD_DATA 0x0C
+#define VT596_PROC_CALL 0x10
#define VT596_BLOCK_DATA 0x14
#define VT596_I2C_BLOCK_DATA 0x34
@@ -232,6 +234,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
}
size = VT596_WORD_DATA;
break;
+ case I2C_SMBUS_PROC_CALL:
+ outb_p(command, SMBHSTCMD);
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ size = VT596_PROC_CALL;
+ break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (!(vt596_features & FEATURE_I2CBLOCK))
goto exit_unsupported;
@@ -262,6 +270,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
if (status)
return status;
+ if (size == VT596_PROC_CALL)
+ read_write = I2C_SMBUS_READ;
+
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
return 0;
@@ -271,6 +282,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
data->byte = inb_p(SMBHSTDAT0);
break;
case VT596_WORD_DATA:
+ case VT596_PROC_CALL:
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
break;
case VT596_I2C_BLOCK_DATA:
@@ -295,7 +307,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
{
u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
if (vt596_features & FEATURE_I2CBLOCK)
func |= I2C_FUNC_SMBUS_I2C_BLOCK;
@@ -396,6 +408,7 @@ found:
switch (pdev->device) {
case PCI_DEVICE_ID_VIA_CX700:
+ case PCI_DEVICE_ID_VIA_VX800:
case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
case PCI_DEVICE_ID_VIA_8237A:
@@ -459,6 +472,8 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index a95cb9465d6..17356827b93 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -172,4 +172,15 @@ config MENELAUS
and other features that are often used in portable devices like
cell phones and PDAs.
+config MCU_MPC8349EMITX
+ tristate "MPC8349E-mITX MCU driver"
+ depends on I2C && PPC_83xx
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here to enable soft power-off functionality on the Freescale
+ boards with the MPC8349E-mITX-compatible MCU chips. This driver will
+ also register MCU GPIOs with the generic GPIO API, so you'll able
+ to use MCU pins as GPIOs.
+
endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 39e3e69ed12..ca520fa143d 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
+obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 4655b794ebe..28902ebd553 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -49,10 +49,9 @@ MODULE_LICENSE("GPL");
struct isp1301 {
struct otg_transceiver otg;
- struct i2c_client client;
+ struct i2c_client *client;
void (*i2c_release)(struct device *dev);
- int irq;
int irq_type;
u32 last_otg_ctrl;
@@ -138,14 +137,6 @@ static inline void notresponding(struct isp1301 *isp)
/*-------------------------------------------------------------------------*/
-/* only two addresses possible */
-#define ISP_BASE 0x2c
-static unsigned short normal_i2c[] = {
- ISP_BASE, ISP_BASE + 1,
- I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
static struct i2c_driver isp1301_driver;
/* smbus apis are used for portability */
@@ -153,25 +144,25 @@ static struct i2c_driver isp1301_driver;
static inline u8
isp1301_get_u8(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+ return i2c_smbus_read_byte_data(isp->client, reg + 0);
}
static inline int
isp1301_get_u16(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_word_data(&isp->client, reg);
+ return i2c_smbus_read_word_data(isp->client, reg);
}
static inline int
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
}
static inline int
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
}
/*-------------------------------------------------------------------------*/
@@ -349,10 +340,10 @@ isp1301_defer_work(struct isp1301 *isp, int work)
int status;
if (isp && !test_and_set_bit(work, &isp->todo)) {
- (void) get_device(&isp->client.dev);
+ (void) get_device(&isp->client->dev);
status = schedule_work(&isp->work);
if (!status && !isp->working)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work item %d may be lost\n", work);
}
}
@@ -1135,7 +1126,7 @@ isp1301_work(struct work_struct *work)
/* transfer state from otg engine to isp1301 */
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
otg_update_isp(isp);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
#endif
/* transfer state from isp1301 to otg engine */
@@ -1143,7 +1134,7 @@ isp1301_work(struct work_struct *work)
u8 stat = isp1301_clear_latch(isp);
isp_update_otg(isp, stat);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
@@ -1178,7 +1169,7 @@ isp1301_work(struct work_struct *work)
}
host_resume(isp);
// mdelay(10);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
@@ -1187,15 +1178,15 @@ isp1301_work(struct work_struct *work)
if (!stop)
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
#endif
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (isp->todo)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work done, todo = 0x%lx\n",
isp->todo);
if (stop) {
- dev_dbg(&isp->client.dev, "stop\n");
+ dev_dbg(&isp->client->dev, "stop\n");
break;
}
} while (isp->todo);
@@ -1219,7 +1210,7 @@ static void isp1301_release(struct device *dev)
{
struct isp1301 *isp;
- isp = container_of(dev, struct isp1301, client.dev);
+ isp = dev_get_drvdata(dev);
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
if (isp->i2c_release)
@@ -1229,15 +1220,15 @@ static void isp1301_release(struct device *dev)
static struct isp1301 *the_transceiver;
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *i2c)
{
struct isp1301 *isp;
- isp = container_of(i2c, struct isp1301, client);
+ isp = i2c_get_clientdata(i2c);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
- free_irq(isp->irq, isp);
+ free_irq(i2c->irq, isp);
#ifdef CONFIG_USB_OTG
otg_unbind(isp);
#endif
@@ -1252,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
put_device(&i2c->dev);
the_transceiver = 0;
- return i2c_detach_client(i2c);
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -1285,7 +1276,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
- dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+ dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
return 0;
}
@@ -1310,7 +1301,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
#ifdef CONFIG_USB_OTG
isp->otg.host = host;
- dev_dbg(&isp->client.dev, "registered host\n");
+ dev_dbg(&isp->client->dev, "registered host\n");
host_suspend(isp);
if (isp->otg.gadget)
return isp1301_otg_enable(isp);
@@ -1325,7 +1316,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
if (machine_is_omap_h2())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
- dev_info(&isp->client.dev, "A-Host sessions ok\n");
+ dev_info(&isp->client->dev, "A-Host sessions ok\n");
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
@@ -1343,7 +1334,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
return 0;
#else
- dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "host sessions not allowed\n");
return -EINVAL;
#endif
@@ -1370,7 +1361,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
#ifdef CONFIG_USB_OTG
isp->otg.gadget = gadget;
- dev_dbg(&isp->client.dev, "registered gadget\n");
+ dev_dbg(&isp->client->dev, "registered gadget\n");
/* gadget driver may be suspended until vbus_connect () */
if (isp->otg.host)
return isp1301_otg_enable(isp);
@@ -1395,7 +1386,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
INTR_SESS_VLD);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
INTR_VBUS_VLD);
- dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+ dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __func__);
/* If this has a Mini-AB connector, this mode is highly
@@ -1408,7 +1399,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
return 0;
#else
- dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
return -EINVAL;
#endif
}
@@ -1508,12 +1499,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
/*-------------------------------------------------------------------------*/
-/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *i2c)
{
int status;
struct isp1301 *isp;
- struct i2c_client *i2c;
if (the_transceiver)
return 0;
@@ -1527,37 +1516,19 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
isp->timer.function = isp1301_timer;
isp->timer.data = (unsigned long) isp;
- isp->irq = -1;
- isp->client.addr = address;
- i2c_set_clientdata(&isp->client, isp);
- isp->client.adapter = bus;
- isp->client.driver = &isp1301_driver;
- strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
- i2c = &isp->client;
-
- /* if this is a true probe, verify the chip ... */
- if (kind < 0) {
- status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
- if (status != I2C_VENDOR_ID_PHILIPS) {
- dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
- address, status);
- goto fail1;
- }
- status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
- if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
- dev_dbg(&bus->dev, "%d not isp1301, %d\n",
- address, status);
- goto fail1;
- }
- }
+ i2c_set_clientdata(i2c, isp);
+ isp->client = i2c;
- status = i2c_attach_client(i2c);
- if (status < 0) {
- dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
- DRIVER_NAME, address, status);
-fail1:
- kfree(isp);
- return 0;
+ /* verify the chip (shouldn't be necesary) */
+ status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+ if (status != I2C_VENDOR_ID_PHILIPS) {
+ dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+ goto fail;
+ }
+ status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+ if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+ dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+ goto fail;
}
isp->i2c_release = i2c->dev.release;
i2c->dev.release = isp1301_release;
@@ -1586,7 +1557,7 @@ fail1:
status = otg_bind(isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't bind OTG\n");
- goto fail2;
+ goto fail;
}
#endif
@@ -1599,26 +1570,21 @@ fail1:
/* IRQ wired at M14 */
omap_cfg_reg(M14_1510_GPIO2);
- isp->irq = OMAP_GPIO_IRQ(2);
if (gpio_request(2, "isp1301") == 0)
gpio_direction_input(2);
isp->irq_type = IRQF_TRIGGER_FALLING;
}
isp->irq_type |= IRQF_SAMPLE_RANDOM;
- status = request_irq(isp->irq, isp1301_irq,
+ status = request_irq(i2c->irq, isp1301_irq,
isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
- isp->irq, status);
-#ifdef CONFIG_USB_OTG
-fail2:
-#endif
- i2c_detach_client(i2c);
- goto fail1;
+ i2c->irq, status);
+ goto fail;
}
- isp->otg.dev = &isp->client.dev;
+ isp->otg.dev = &i2c->dev;
isp->otg.label = DRIVER_NAME;
isp->otg.set_host = isp1301_set_host,
@@ -1649,22 +1615,25 @@ fail2:
status);
return 0;
-}
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
- if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -EINVAL;
- return i2c_probe(bus, &addr_data, isp1301_probe);
+fail:
+ kfree(isp);
+ return -ENODEV;
}
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301_omap", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
static struct i2c_driver isp1301_driver = {
.driver = {
.name = "isp1301_omap",
},
- .attach_adapter = isp1301_scan_bus,
- .detach_client = isp1301_detach_client,
+ .probe = isp1301_probe,
+ .remove = __exit_p(isp1301_remove),
+ .id_table = isp1301_id,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c
new file mode 100644
index 00000000000..82a9bcb858b
--- /dev/null
+++ b/drivers/i2c/chips/mcu_mpc8349emitx.c
@@ -0,0 +1,209 @@
+/*
+ * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU
+ *
+ * Copyright (c) 2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+/*
+ * I don't have specifications for the MCU firmware, I found this register
+ * and bits positions by the trial&error method.
+ */
+#define MCU_REG_CTRL 0x20
+#define MCU_CTRL_POFF 0x40
+
+#define MCU_NUM_GPIO 2
+
+struct mcu {
+ struct mutex lock;
+ struct device_node *np;
+ struct i2c_client *client;
+ struct of_gpio_chip of_gc;
+ u8 reg_ctrl;
+};
+
+static struct mcu *glob_mcu;
+
+static void mcu_power_off(void)
+{
+ struct mcu *mcu = glob_mcu;
+
+ pr_info("Sending power-off request to the MCU...\n");
+ mutex_lock(&mcu->lock);
+ i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL,
+ mcu->reg_ctrl | MCU_CTRL_POFF);
+ mutex_unlock(&mcu->lock);
+}
+
+static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
+ struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
+ u8 bit = 1 << (4 + gpio);
+
+ mutex_lock(&mcu->lock);
+ if (val)
+ mcu->reg_ctrl &= ~bit;
+ else
+ mcu->reg_ctrl |= bit;
+
+ i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl);
+ mutex_unlock(&mcu->lock);
+}
+
+static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ mcu_gpio_set(gc, gpio, val);
+ return 0;
+}
+
+static int mcu_gpiochip_add(struct mcu *mcu)
+{
+ struct device_node *np;
+ struct of_gpio_chip *of_gc = &mcu->of_gc;
+ struct gpio_chip *gc = &of_gc->gc;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
+ if (!np)
+ return -ENODEV;
+
+ gc->owner = THIS_MODULE;
+ gc->label = np->full_name;
+ gc->can_sleep = 1;
+ gc->ngpio = MCU_NUM_GPIO;
+ gc->base = -1;
+ gc->set = mcu_gpio_set;
+ gc->direction_output = mcu_gpio_dir_out;
+ of_gc->gpio_cells = 2;
+ of_gc->xlate = of_gpio_simple_xlate;
+
+ np->data = of_gc;
+ mcu->np = np;
+
+ /*
+ * We don't want to lose the node, its ->data and ->full_name...
+ * So, if succeeded, we don't put the node here.
+ */
+ ret = gpiochip_add(gc);
+ if (ret)
+ of_node_put(np);
+ return ret;
+}
+
+static int mcu_gpiochip_remove(struct mcu *mcu)
+{
+ int ret;
+
+ ret = gpiochip_remove(&mcu->of_gc.gc);
+ if (ret)
+ return ret;
+ of_node_put(mcu->np);
+
+ return 0;
+}
+
+static int __devinit mcu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mcu *mcu;
+ int ret;
+
+ mcu = kzalloc(sizeof(*mcu), GFP_KERNEL);
+ if (!mcu)
+ return -ENOMEM;
+
+ mutex_init(&mcu->lock);
+ mcu->client = client;
+ i2c_set_clientdata(client, mcu);
+
+ ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
+ if (ret < 0)
+ goto err;
+ mcu->reg_ctrl = ret;
+
+ ret = mcu_gpiochip_add(mcu);
+ if (ret)
+ goto err;
+
+ /* XXX: this is potentially racy, but there is no lock for ppc_md */
+ if (!ppc_md.power_off) {
+ glob_mcu = mcu;
+ ppc_md.power_off = mcu_power_off;
+ dev_info(&client->dev, "will provide power-off service\n");
+ }
+
+ return 0;
+err:
+ kfree(mcu);
+ return ret;
+}
+
+static int __devexit mcu_remove(struct i2c_client *client)
+{
+ struct mcu *mcu = i2c_get_clientdata(client);
+ int ret;
+
+ if (glob_mcu == mcu) {
+ ppc_md.power_off = NULL;
+ glob_mcu = NULL;
+ }
+
+ ret = mcu_gpiochip_remove(mcu);
+ if (ret)
+ return ret;
+ i2c_set_clientdata(client, NULL);
+ kfree(mcu);
+ return 0;
+}
+
+static const struct i2c_device_id mcu_ids[] = {
+ { "mcu-mpc8349emitx", },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mcu_ids);
+
+static struct i2c_driver mcu_driver = {
+ .driver = {
+ .name = "mcu-mpc8349emitx",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcu_probe,
+ .remove = __devexit_p(mcu_remove),
+ .id_table = mcu_ids,
+};
+
+static int __init mcu_init(void)
+{
+ return i2c_add_driver(&mcu_driver);
+}
+module_init(mcu_init);
+
+static void __exit mcu_exit(void)
+{
+ i2c_del_driver(&mcu_driver);
+}
+module_exit(mcu_exit);
+
+MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
+ "MPC8349E-mITX-compatible MCU");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index cf02e8fceb4..acf8b9d5f57 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -456,14 +456,17 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
/* offsets 0..3 == GPIO1..GPIO4
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
+ * offset 6 == vibrator motor driver
*/
static void
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 4)
tps65010_set_gpio_out_value(offset + 1, value);
- else
+ else if (offset < 6)
tps65010_set_led(offset - 3, value ? ON : OFF);
+ else
+ tps65010_set_vib(value);
}
static int
@@ -477,8 +480,10 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
if (!(tps->outmask & (1 << offset)))
return -EINVAL;
tps65010_set_gpio_out_value(offset + 1, value);
- } else
+ } else if (offset < 6)
tps65010_set_led(offset - 3, value ? ON : OFF);
+ else
+ tps65010_set_vib(value);
return 0;
}
@@ -646,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
tps->chip.get = tps65010_gpio_get;
tps->chip.base = board->base;
- tps->chip.ngpio = 6;
+ tps->chip.ngpio = 7;
tps->chip.can_sleep = 1;
status = gpiochip_add(&tps->chip);
@@ -675,6 +680,7 @@ static const struct i2c_device_id tps65010_id[] = {
{ "tps65011", TPS65011 },
{ "tps65012", TPS65012 },
{ "tps65013", TPS65013 },
+ { "tps65014", TPS65011 }, /* tps65011 charging at 6.5V max */
{ }
};
MODULE_DEVICE_TABLE(i2c, tps65010_id);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b346a687ab5..42e852d79ff 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0, dummy;
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p)))
+ return -EAGAIN;
+
mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock);
INIT_LIST_HEAD(&adap->clients);
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p)))
+ return -EAGAIN;
+
/* new style driver methods can't mix with legacy ones */
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
@@ -978,7 +986,10 @@ static void __exit i2c_exit(void)
bus_unregister(&i2c_bus_type);
}
-subsys_initcall(i2c_init);
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
module_exit(i2c_exit);
/* ----------------------------------------------------
@@ -1677,6 +1688,28 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
EXPORT_SYMBOL(i2c_smbus_write_word_data);
/**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ int status;
+ data.word = value;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_PROC_CALL, &data);
+ return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
* i2c_smbus_read_block_data - SMBus "block read" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 6c6dd2faced..74a369a6116 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -4,7 +4,7 @@
# Select HAVE_IDE if IDE is supported
config HAVE_IDE
- def_bool n
+ bool
menuconfig IDE
tristate "ATA/ATAPI/MFM/RLL support"
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 6791be81eb2..839d1c9622f 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -455,10 +455,10 @@ static void xpad_bulk_out(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __func__, urb->status);
break;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __func__, urb->status);
}
}
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 039787f81ed..69e674ecf19 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -72,12 +72,9 @@ static unsigned int *col_gpios;
static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
{
int col;
- for (col = 0; col < omap_kp->cols; col++) {
- if (value & (1 << col))
- omap_set_gpio_dataout(col_gpios[col], 1);
- else
- omap_set_gpio_dataout(col_gpios[col], 0);
- }
+
+ for (col = 0; col < omap_kp->cols; col++)
+ gpio_set_value(col_gpios[col], value & (1 << col));
}
static u8 get_row_gpio_val(struct omap_kp *omap_kp)
@@ -86,7 +83,7 @@ static u8 get_row_gpio_val(struct omap_kp *omap_kp)
u8 value = 0;
for (row = 0; row < omap_kp->rows; row++) {
- if (omap_get_gpio_datain(row_gpios[row]))
+ if (gpio_get_value(row_gpios[row]))
value |= (1 << row);
}
return value;
@@ -333,23 +330,23 @@ static int __init omap_kp_probe(struct platform_device *pdev)
if (cpu_is_omap24xx()) {
/* Cols: outputs */
for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
- if (omap_request_gpio(col_gpios[col_idx]) < 0) {
+ if (gpio_request(col_gpios[col_idx], "omap_kp_col") < 0) {
printk(KERN_ERR "Failed to request"
"GPIO%d for keypad\n",
col_gpios[col_idx]);
goto err1;
}
- omap_set_gpio_direction(col_gpios[col_idx], 0);
+ gpio_direction_output(col_gpios[col_idx], 0);
}
/* Rows: inputs */
for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
- if (omap_request_gpio(row_gpios[row_idx]) < 0) {
+ if (gpio_request(row_gpios[row_idx], "omap_kp_row") < 0) {
printk(KERN_ERR "Failed to request"
"GPIO%d for keypad\n",
row_gpios[row_idx]);
goto err2;
}
- omap_set_gpio_direction(row_gpios[row_idx], 1);
+ gpio_direction_input(row_gpios[row_idx]);
}
} else {
col_idx = 0;
@@ -418,10 +415,10 @@ err3:
device_remove_file(&pdev->dev, &dev_attr_enable);
err2:
for (i = row_idx - 1; i >=0; i--)
- omap_free_gpio(row_gpios[i]);
+ gpio_free(row_gpios[i]);
err1:
for (i = col_idx - 1; i >=0; i--)
- omap_free_gpio(col_gpios[i]);
+ gpio_free(col_gpios[i]);
kfree(omap_kp);
input_free_device(input_dev);
@@ -438,9 +435,9 @@ static int omap_kp_remove(struct platform_device *pdev)
if (cpu_is_omap24xx()) {
int i;
for (i = 0; i < omap_kp->cols; i++)
- omap_free_gpio(col_gpios[i]);
+ gpio_free(col_gpios[i]);
for (i = 0; i < omap_kp->rows; i++) {
- omap_free_gpio(row_gpios[i]);
+ gpio_free(row_gpios[i]);
free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
}
} else {
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index daa9d422033..82ec6b1b646 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -458,35 +458,35 @@ static int hp_sdc_rtc_proc_output (char *buf)
p += sprintf(p, "i8042 rtc\t: READ FAILED!\n");
} else {
p += sprintf(p, "i8042 rtc\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_fhs(&tv)) {
p += sprintf(p, "handshake\t: READ FAILED!\n");
} else {
p += sprintf(p, "handshake\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_mt(&tv)) {
p += sprintf(p, "alarm\t\t: READ FAILED!\n");
} else {
p += sprintf(p, "alarm\t\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_dt(&tv)) {
p += sprintf(p, "delay\t\t: READ FAILED!\n");
} else {
p += sprintf(p, "delay\t\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
if (hp_sdc_rtc_read_ct(&tv)) {
p += sprintf(p, "periodic\t: READ FAILED!\n");
} else {
p += sprintf(p, "periodic\t: %ld.%02d seconds\n",
- tv.tv_sec, tv.tv_usec/1000);
+ tv.tv_sec, (int)tv.tv_usec/1000);
}
p += sprintf(p,
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 0d395979b2d..bfe49243f38 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -323,7 +323,7 @@ static void hp_sdc_tasklet(unsigned long foo)
* it back to the application. and be less verbose.
*/
printk(KERN_WARNING PREFIX "read timeout (%ius)!\n",
- tv.tv_usec - hp_sdc.rtv.tv_usec);
+ (int)(tv.tv_usec - hp_sdc.rtv.tv_usec));
curr->idx += hp_sdc.rqty;
hp_sdc.rqty = 0;
tmp = curr->seq[curr->actidx];
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index f451c7351a9..847f4aad7ed 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -67,7 +67,7 @@ static inline int i8042_platform_init(void)
* On some platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on such boxes.
*/
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
if (check_legacy_ioport(I8042_DATA_REG))
return -ENODEV;
#endif
diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c
index e92b1ba4b45..c2f51cc5076 100644
--- a/drivers/isdn/mISDN/dsp_cmx.c
+++ b/drivers/isdn/mISDN/dsp_cmx.c
@@ -452,10 +452,10 @@ one_member:
if (finddsp->features.pcm_id == dsp->features.pcm_id) {
if (finddsp->pcm_slot_rx >= 0 &&
finddsp->pcm_slot_rx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_tx] = 0;
+ freeslots[finddsp->pcm_slot_rx] = 0;
if (finddsp->pcm_slot_tx >= 0 &&
finddsp->pcm_slot_tx < sizeof(freeslots))
- freeslots[finddsp->pcm_slot_rx] = 0;
+ freeslots[finddsp->pcm_slot_tx] = 0;
}
}
i = 0;
diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c
index e7462924b50..875fabe16e3 100644
--- a/drivers/isdn/mISDN/timerdev.c
+++ b/drivers/isdn/mISDN/timerdev.c
@@ -61,7 +61,7 @@ mISDN_open(struct inode *ino, struct file *filep)
init_waitqueue_head(&dev->wait);
filep->private_data = dev;
__module_get(THIS_MODULE);
- return 0;
+ return nonseekable_open(ino, filep);
}
static int
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 07d92c11b5d..2281b5098e9 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -30,6 +30,20 @@ config BLK_DEV_MD
If unsure, say N.
+config MD_AUTODETECT
+ bool "Autodetect RAID arrays during kernel boot"
+ depends on BLK_DEV_MD=y
+ default y
+ ---help---
+ If you say Y here, then the kernel will try to autodetect raid
+ arrays as part of its boot process.
+
+ If you don't use raid and say Y, this autodetection can cause
+ a several-second delay in the boot time due to various
+ synchronisation steps that are part of this step.
+
+ If unsure, say Y.
+
config MD_LINEAR
tristate "Linear (append) mode"
depends on BLK_DEV_MD
diff --git a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile
index 2c2e39aa1ef..b0982dacfd0 100644
--- a/drivers/message/i2o/Makefile
+++ b/drivers/message/i2o/Makefile
@@ -5,7 +5,7 @@
# In the future, some of these should be built conditionally.
#
-i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o
+i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o memory.o
i2o_bus-y += bus-osm.o
i2o_config-y += config-osm.o
obj-$(CONFIG_I2O) += i2o_core.o
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
index 8774c670e66..54c2e9ae23e 100644
--- a/drivers/message/i2o/device.c
+++ b/drivers/message/i2o/device.c
@@ -467,7 +467,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
res.virt = NULL;
- if (i2o_dma_alloc(dev, &res, reslen, GFP_KERNEL))
+ if (i2o_dma_alloc(dev, &res, reslen))
return -ENOMEM;
msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 6cbcc21de51..56faef1a1d5 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -388,8 +388,8 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
dev = &c->pdev->dev;
- if (i2o_dma_realloc
- (dev, &c->dlct, le32_to_cpu(sb->expected_lct_size), GFP_KERNEL))
+ if (i2o_dma_realloc(dev, &c->dlct,
+ le32_to_cpu(sb->expected_lct_size)))
return -ENOMEM;
msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 4238de98d4a..a3fabdbe6ca 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -260,7 +260,7 @@ static int i2o_cfg_swdl(unsigned long arg)
if (IS_ERR(msg))
return PTR_ERR(msg);
- if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+ if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
i2o_msg_nop(c, msg);
return -ENOMEM;
}
@@ -339,7 +339,7 @@ static int i2o_cfg_swul(unsigned long arg)
if (IS_ERR(msg))
return PTR_ERR(msg);
- if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize, GFP_KERNEL)) {
+ if (i2o_dma_alloc(&c->pdev->dev, &buffer, fragsize)) {
i2o_msg_nop(c, msg);
return -ENOMEM;
}
@@ -634,9 +634,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
sg_size = sg[i].flag_count & 0xffffff;
p = &(sg_list[sg_index]);
/* Allocate memory for the transfer */
- if (i2o_dma_alloc
- (&c->pdev->dev, p, sg_size,
- PCI_DMA_BIDIRECTIONAL)) {
+ if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
printk(KERN_DEBUG
"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
c->name, sg_size, i, sg_count);
@@ -780,12 +778,11 @@ static int i2o_cfg_passthru(unsigned long arg)
u32 size = 0;
u32 reply_size = 0;
u32 rcode = 0;
- void *sg_list[SG_TABLESIZE];
+ struct i2o_dma sg_list[SG_TABLESIZE];
u32 sg_offset = 0;
u32 sg_count = 0;
int sg_index = 0;
u32 i = 0;
- void *p = NULL;
i2o_status_block *sb;
struct i2o_message *msg;
unsigned int iop;
@@ -842,6 +839,7 @@ static int i2o_cfg_passthru(unsigned long arg)
memset(sg_list, 0, sizeof(sg_list[0]) * SG_TABLESIZE);
if (sg_offset) {
struct sg_simple_element *sg;
+ struct i2o_dma *p;
if (sg_offset * 4 >= size) {
rcode = -EFAULT;
@@ -871,22 +869,22 @@ static int i2o_cfg_passthru(unsigned long arg)
goto sg_list_cleanup;
}
sg_size = sg[i].flag_count & 0xffffff;
+ p = &(sg_list[sg_index]);
+ if (i2o_dma_alloc(&c->pdev->dev, p, sg_size)) {
/* Allocate memory for the transfer */
- p = kmalloc(sg_size, GFP_KERNEL);
- if (!p) {
printk(KERN_DEBUG
"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
c->name, sg_size, i, sg_count);
rcode = -ENOMEM;
goto sg_list_cleanup;
}
- sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
+ sg_index++;
/* Copy in the user's SG buffer if necessary */
if (sg[i].
flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR */ ) {
// TODO 64bit fix
if (copy_from_user
- (p, (void __user *)sg[i].addr_bus,
+ (p->virt, (void __user *)sg[i].addr_bus,
sg_size)) {
printk(KERN_DEBUG
"%s: Could not copy SG buf %d FROM user\n",
@@ -895,8 +893,7 @@ static int i2o_cfg_passthru(unsigned long arg)
goto sg_list_cleanup;
}
}
- //TODO 64bit fix
- sg[i].addr_bus = virt_to_bus(p);
+ sg[i].addr_bus = p->phys;
}
}
@@ -908,7 +905,7 @@ static int i2o_cfg_passthru(unsigned long arg)
}
if (sg_offset) {
- u32 rmsg[128];
+ u32 rmsg[I2O_OUTBOUND_MSG_FRAME_SIZE];
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
// TODO 64bit fix
@@ -942,11 +939,11 @@ static int i2o_cfg_passthru(unsigned long arg)
sg_size = sg[j].flag_count & 0xffffff;
// TODO 64bit fix
if (copy_to_user
- ((void __user *)sg[j].addr_bus, sg_list[j],
+ ((void __user *)sg[j].addr_bus, sg_list[j].virt,
sg_size)) {
printk(KERN_WARNING
"%s: Could not copy %p TO user %x\n",
- c->name, sg_list[j],
+ c->name, sg_list[j].virt,
sg[j].addr_bus);
rcode = -EFAULT;
goto sg_list_cleanup;
@@ -973,7 +970,7 @@ sg_list_cleanup:
}
for (i = 0; i < sg_index; i++)
- kfree(sg_list[i]);
+ i2o_dma_free(&c->pdev->dev, &sg_list[i]);
cleanup:
kfree(reply);
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index da715e11c1b..be2b5926d26 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -1004,7 +1004,7 @@ static int i2o_hrt_get(struct i2o_controller *c)
size = hrt->num_entries * hrt->entry_len << 2;
if (size > c->hrt.len) {
- if (i2o_dma_realloc(dev, &c->hrt, size, GFP_KERNEL))
+ if (i2o_dma_realloc(dev, &c->hrt, size))
return -ENOMEM;
else
hrt = c->hrt.virt;
diff --git a/drivers/message/i2o/memory.c b/drivers/message/i2o/memory.c
new file mode 100644
index 00000000000..f5cc95c564e
--- /dev/null
+++ b/drivers/message/i2o/memory.c
@@ -0,0 +1,313 @@
+/*
+ * Functions to handle I2O memory
+ *
+ * Pulled from the inlines in i2o headers and uninlined
+ *
+ *
+ * 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/i2o.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/* Protects our 32/64bit mask switching */
+static DEFINE_MUTEX(mem_lock);
+
+/**
+ * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ * @c: I2O controller for which the calculation should be done
+ * @body_size: maximum body size used for message in 32-bit words.
+ *
+ * Return the maximum number of SG elements in a SG list.
+ */
+u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ u16 sg_count =
+ (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+ body_size;
+
+ if (c->pae_support) {
+ /*
+ * for 64-bit a SG attribute element must be added and each
+ * SG element needs 12 bytes instead of 8.
+ */
+ sg_count -= 2;
+ sg_count /= 3;
+ } else
+ sg_count /= 2;
+
+ if (c->short_req && (sg_count > 8))
+ sg_count = 8;
+
+ return sg_count;
+}
+EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
+
+
+/**
+ * i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ * @c: I2O controller
+ * @ptr: pointer to the data which should be mapped
+ * @size: size of data in bytes
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ * SG list if the allocation was successful.
+ *
+ * Returns DMA address which must be checked for failures using
+ * dma_mapping_error().
+ */
+dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+ size_t size,
+ enum dma_data_direction direction,
+ u32 ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 *mptr = *sg_ptr;
+ dma_addr_t dma_addr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0xd4000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0xd0000000;
+ break;
+ default:
+ return 0;
+ }
+
+ dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+ if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ *mptr++ = cpu_to_le32(0x7C020002);
+ *mptr++ = cpu_to_le32(PAGE_SIZE);
+ }
+#endif
+
+ *mptr++ = cpu_to_le32(sg_flags | size);
+ *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
+#endif
+ *sg_ptr = mptr;
+ }
+ return dma_addr;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_single);
+
+/**
+ * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ * @c: I2O controller
+ * @sg: SG list to be mapped
+ * @sg_count: number of elements in the SG list
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ * list if the allocation was successful.
+ *
+ * Returns 0 on failure or 1 on success.
+ */
+int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
+ int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 *mptr = *sg_ptr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0x14000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0x10000000;
+ break;
+ default:
+ return 0;
+ }
+
+ sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+ if (!sg_count)
+ return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ *mptr++ = cpu_to_le32(0x7C020002);
+ *mptr++ = cpu_to_le32(PAGE_SIZE);
+ }
+#endif
+
+ while (sg_count-- > 0) {
+ if (!sg_count)
+ sg_flags |= 0xC0000000;
+ *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
+ *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
+#endif
+ sg = sg_next(sg);
+ }
+ *sg_ptr = mptr;
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
+
+/**
+ * i2o_dma_alloc - Allocate DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which should get the DMA buffer
+ * @len: length of the new DMA memory
+ *
+ * Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ * Returns 0 on success or -ENOMEM on failure.
+ */
+int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int dma_64 = 0;
+
+ mutex_lock(&mem_lock);
+ if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
+ dma_64 = 1;
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+ mutex_unlock(&mem_lock);
+ return -ENOMEM;
+ }
+ }
+
+ addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
+
+ if ((sizeof(dma_addr_t) > 4) && dma_64)
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+ printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+ mutex_unlock(&mem_lock);
+
+ if (!addr->virt)
+ return -ENOMEM;
+
+ memset(addr->virt, 0, len);
+ addr->len = len;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_alloc);
+
+
+/**
+ * i2o_dma_free - Free DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which contains the DMA buffer
+ *
+ * Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+ if (addr->virt) {
+ if (addr->phys)
+ dma_free_coherent(dev, addr->len, addr->virt,
+ addr->phys);
+ else
+ kfree(addr->virt);
+ addr->virt = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(i2o_dma_free);
+
+
+/**
+ * i2o_dma_realloc - Realloc DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: pointer to a i2o_dma struct DMA buffer
+ * @len: new length of memory
+ *
+ * If there was something allocated in the addr, free it first. If len > 0
+ * than try to allocate it and write the addresses back to the addr
+ * structure. If len == 0 set the virtual address to NULL.
+ *
+ * Returns the 0 on success or negative error code on failure.
+ */
+int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+ i2o_dma_free(dev, addr);
+
+ if (len)
+ return i2o_dma_alloc(dev, addr, len);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_realloc);
+
+/*
+ * i2o_pool_alloc - Allocate an slab cache and mempool
+ * @mempool: pointer to struct i2o_pool to write data into.
+ * @name: name which is used to identify cache
+ * @size: size of each object
+ * @min_nr: minimum number of objects
+ *
+ * First allocates a slab cache with name and size. Then allocates a
+ * mempool which uses the slab cache for allocation and freeing.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+ size_t size, int min_nr)
+{
+ pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!pool->name)
+ goto exit;
+ strcpy(pool->name, name);
+
+ pool->slab =
+ kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!pool->slab)
+ goto free_name;
+
+ pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
+ if (!pool->mempool)
+ goto free_slab;
+
+ return 0;
+
+free_slab:
+ kmem_cache_destroy(pool->slab);
+
+free_name:
+ kfree(pool->name);
+
+exit:
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(i2o_pool_alloc);
+
+/*
+ * i2o_pool_free - Free slab cache and mempool again
+ * @mempool: pointer to struct i2o_pool which should be freed
+ *
+ * Note that you have to return all objects to the mempool again before
+ * calling i2o_pool_free().
+ */
+void i2o_pool_free(struct i2o_pool *pool)
+{
+ mempool_destroy(pool->mempool);
+ kmem_cache_destroy(pool->slab);
+ kfree(pool->name);
+};
+EXPORT_SYMBOL_GPL(i2o_pool_free);
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index 685a89547a5..610ef1204e6 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -186,31 +186,29 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
}
}
- if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
+ if (i2o_dma_alloc(dev, &c->status, 8)) {
i2o_pci_free(c);
return -ENOMEM;
}
- if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt), GFP_KERNEL)) {
+ if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
i2o_pci_free(c);
return -ENOMEM;
}
- if (i2o_dma_alloc(dev, &c->dlct, 8192, GFP_KERNEL)) {
+ if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
i2o_pci_free(c);
return -ENOMEM;
}
- if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block),
- GFP_KERNEL)) {
+ if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
i2o_pci_free(c);
return -ENOMEM;
}
- if (i2o_dma_alloc
- (dev, &c->out_queue,
- I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
- sizeof(u32), GFP_KERNEL)) {
+ if (i2o_dma_alloc(dev, &c->out_queue,
+ I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+ sizeof(u32))) {
i2o_pci_free(c);
return -ENOMEM;
}
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 0dae245c625..5eff8ad834d 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -87,6 +87,44 @@ config MFD_TC6393XB
help
Support for Toshiba Mobile IO Controller TC6393XB
+config MFD_WM8400
+ tristate "Support Wolfson Microelectronics WM8400"
+ help
+ Support for the Wolfson Microelecronics WM8400 PMIC and audio
+ CODEC. This driver adds provides common support for accessing
+ the device, additional drivers must be enabled in order to use
+ the functionality of the device.
+
+config MFD_WM8350
+ tristate
+
+config MFD_WM8350_CONFIG_MODE_0
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_1
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_2
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_CONFIG_MODE_3
+ bool
+ depends on MFD_WM8350
+
+config MFD_WM8350_I2C
+ tristate "Support Wolfson Microelectronics WM8350 with I2C"
+ select MFD_WM8350
+ depends on I2C
+ help
+ The WM8350 is an integrated audio and power management
+ subsystem with watchdog and RTC functionality for embedded
+ systems. This option enables core support for the WM8350 with
+ I2C as the control interface. Additional options must be
+ selected to enable support for the functionality of the chip.
+
endmenu
menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 6abebe36441..759b1fe1c89 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -12,6 +12,11 @@ obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o
+obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
+wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
+obj-$(CONFIG_MFD_WM8350) += wm8350.o
+obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
+
obj-$(CONFIG_MFD_CORE) += mfd-core.o
obj-$(CONFIG_MCP) += mcp-core.o
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
new file mode 100644
index 00000000000..25a7a5d08bc
--- /dev/null
+++ b/drivers/mfd/wm8350-core.c
@@ -0,0 +1,1273 @@
+/*
+ * wm8350-core.c -- Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood, Mark Brown
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/bug.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/comparator.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+#define WM8350_UNLOCK_KEY 0x0013
+#define WM8350_LOCK_KEY 0x0000
+
+#define WM8350_CLOCK_CONTROL_1 0x28
+#define WM8350_AIF_TEST 0x74
+
+/* debug */
+#define WM8350_BUS_DEBUG 0
+#if WM8350_BUS_DEBUG
+#define dump(regs, src) do { \
+ int i_; \
+ u16 *src_ = src; \
+ printk(KERN_DEBUG); \
+ for (i_ = 0; i_ < regs; i_++) \
+ printk(" 0x%4.4x", *src_++); \
+ printk("\n"); \
+} while (0);
+#else
+#define dump(bytes, src)
+#endif
+
+#define WM8350_LOCK_DEBUG 0
+#if WM8350_LOCK_DEBUG
+#define ldbg(format, arg...) printk(format, ## arg)
+#else
+#define ldbg(format, arg...)
+#endif
+
+/*
+ * WM8350 Device IO
+ */
+static DEFINE_MUTEX(io_mutex);
+static DEFINE_MUTEX(reg_lock_mutex);
+static DEFINE_MUTEX(auxadc_mutex);
+
+/* Perform a physical read from the device.
+ */
+static int wm8350_phys_read(struct wm8350 *wm8350, u8 reg, int num_regs,
+ u16 *dest)
+{
+ int i, ret;
+ int bytes = num_regs * 2;
+
+ dev_dbg(wm8350->dev, "volatile read\n");
+ ret = wm8350->read_dev(wm8350, reg, bytes, (char *)dest);
+
+ for (i = reg; i < reg + num_regs; i++) {
+ /* Cache is CPU endian */
+ dest[i - reg] = be16_to_cpu(dest[i - reg]);
+
+ /* Satisfy non-volatile bits from cache */
+ dest[i - reg] &= wm8350_reg_io_map[i].vol;
+ dest[i - reg] |= wm8350->reg_cache[i];
+
+ /* Mask out non-readable bits */
+ dest[i - reg] &= wm8350_reg_io_map[i].readable;
+ }
+
+ dump(num_regs, dest);
+
+ return ret;
+}
+
+static int wm8350_read(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *dest)
+{
+ int i;
+ int end = reg + num_regs;
+ int ret = 0;
+ int bytes = num_regs * 2;
+
+ if (wm8350->read_dev == NULL)
+ return -ENODEV;
+
+ if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+ dev_err(wm8350->dev, "invalid reg %x\n",
+ reg + num_regs - 1);
+ return -EINVAL;
+ }
+
+ dev_dbg(wm8350->dev,
+ "%s R%d(0x%2.2x) %d regs\n", __func__, reg, reg, num_regs);
+
+#if WM8350_BUS_DEBUG
+ /* we can _safely_ read any register, but warn if read not supported */
+ for (i = reg; i < end; i++) {
+ if (!wm8350_reg_io_map[i].readable)
+ dev_warn(wm8350->dev,
+ "reg R%d is not readable\n", i);
+ }
+#endif
+
+ /* if any volatile registers are required, then read back all */
+ for (i = reg; i < end; i++)
+ if (wm8350_reg_io_map[i].vol)
+ return wm8350_phys_read(wm8350, reg, num_regs, dest);
+
+ /* no volatiles, then cache is good */
+ dev_dbg(wm8350->dev, "cache read\n");
+ memcpy(dest, &wm8350->reg_cache[reg], bytes);
+ dump(num_regs, dest);
+ return ret;
+}
+
+static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
+{
+ if (reg == WM8350_SECURITY ||
+ wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
+ return 0;
+
+ if ((reg == WM8350_GPIO_CONFIGURATION_I_O) ||
+ (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
+ reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
+ (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
+ reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
+ return 1;
+ return 0;
+}
+
+static int wm8350_write(struct wm8350 *wm8350, u8 reg, int num_regs, u16 *src)
+{
+ int i;
+ int end = reg + num_regs;
+ int bytes = num_regs * 2;
+
+ if (wm8350->write_dev == NULL)
+ return -ENODEV;
+
+ if ((reg + num_regs - 1) > WM8350_MAX_REGISTER) {
+ dev_err(wm8350->dev, "invalid reg %x\n",
+ reg + num_regs - 1);
+ return -EINVAL;
+ }
+
+ /* it's generally not a good idea to write to RO or locked registers */
+ for (i = reg; i < end; i++) {
+ if (!wm8350_reg_io_map[i].writable) {
+ dev_err(wm8350->dev,
+ "attempted write to read only reg R%d\n", i);
+ return -EINVAL;
+ }
+
+ if (is_reg_locked(wm8350, i)) {
+ dev_err(wm8350->dev,
+ "attempted write to locked reg R%d\n", i);
+ return -EINVAL;
+ }
+
+ src[i - reg] &= wm8350_reg_io_map[i].writable;
+
+ wm8350->reg_cache[i] =
+ (wm8350->reg_cache[i] & ~wm8350_reg_io_map[i].writable)
+ | src[i - reg];
+
+ src[i - reg] = cpu_to_be16(src[i - reg]);
+ }
+
+ /* Actually write it out */
+ return wm8350->write_dev(wm8350, reg, bytes, (char *)src);
+}
+
+/*
+ * Safe read, modify, write methods
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err) {
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+ goto out;
+ }
+
+ data &= ~mask;
+ err = wm8350_write(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_clear_bits);
+
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err) {
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+ goto out;
+ }
+
+ data |= mask;
+ err = wm8350_write(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+out:
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_set_bits);
+
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg)
+{
+ u16 data;
+ int err;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, reg, 1, &data);
+ if (err)
+ dev_err(wm8350->dev, "read from reg R%d failed\n", reg);
+
+ mutex_unlock(&io_mutex);
+ return data;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_read);
+
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val)
+{
+ int ret;
+ u16 data = val;
+
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, reg, 1, &data);
+ if (ret)
+ dev_err(wm8350->dev, "write to reg R%d failed\n", reg);
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_write);
+
+int wm8350_block_read(struct wm8350 *wm8350, int start_reg, int regs,
+ u16 *dest)
+{
+ int err = 0;
+
+ mutex_lock(&io_mutex);
+ err = wm8350_read(wm8350, start_reg, regs, dest);
+ if (err)
+ dev_err(wm8350->dev, "block read starting from R%d failed\n",
+ start_reg);
+ mutex_unlock(&io_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_read);
+
+int wm8350_block_write(struct wm8350 *wm8350, int start_reg, int regs,
+ u16 *src)
+{
+ int ret = 0;
+
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, start_reg, regs, src);
+ if (ret)
+ dev_err(wm8350->dev, "block write starting at R%d failed\n",
+ start_reg);
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_block_write);
+
+int wm8350_reg_lock(struct wm8350 *wm8350)
+{
+ u16 key = WM8350_LOCK_KEY;
+ int ret;
+
+ ldbg(__func__);
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+ if (ret)
+ dev_err(wm8350->dev, "lock failed\n");
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_lock);
+
+int wm8350_reg_unlock(struct wm8350 *wm8350)
+{
+ u16 key = WM8350_UNLOCK_KEY;
+ int ret;
+
+ ldbg(__func__);
+ mutex_lock(&io_mutex);
+ ret = wm8350_write(wm8350, WM8350_SECURITY, 1, &key);
+ if (ret)
+ dev_err(wm8350->dev, "unlock failed\n");
+ mutex_unlock(&io_mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_reg_unlock);
+
+static void wm8350_irq_call_handler(struct wm8350 *wm8350, int irq)
+{
+ mutex_lock(&wm8350->irq_mutex);
+
+ if (wm8350->irq[irq].handler)
+ wm8350->irq[irq].handler(wm8350, irq, wm8350->irq[irq].data);
+ else {
+ dev_err(wm8350->dev, "irq %d nobody cared. now masked.\n",
+ irq);
+ wm8350_mask_irq(wm8350, irq);
+ }
+
+ mutex_unlock(&wm8350->irq_mutex);
+}
+
+/*
+ * wm8350_irq_worker actually handles the interrupts. Since all
+ * interrupts are clear on read the IRQ line will be reasserted and
+ * the physical IRQ will be handled again if another interrupt is
+ * asserted while we run - in the normal course of events this is a
+ * rare occurrence so we save I2C/SPI reads.
+ */
+static void wm8350_irq_worker(struct work_struct *work)
+{
+ struct wm8350 *wm8350 = container_of(work, struct wm8350, irq_work);
+ u16 level_one, status1, status2, comp;
+
+ /* TODO: Use block reads to improve performance? */
+ level_one = wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS)
+ & ~wm8350_reg_read(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK);
+ status1 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_1)
+ & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_1_MASK);
+ status2 = wm8350_reg_read(wm8350, WM8350_INT_STATUS_2)
+ & ~wm8350_reg_read(wm8350, WM8350_INT_STATUS_2_MASK);
+ comp = wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS)
+ & ~wm8350_reg_read(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK);
+
+ /* over current */
+ if (level_one & WM8350_OC_INT) {
+ u16 oc;
+
+ oc = wm8350_reg_read(wm8350, WM8350_OVER_CURRENT_INT_STATUS);
+ oc &= ~wm8350_reg_read(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK);
+
+ if (oc & WM8350_OC_LS_EINT) /* limit switch */
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_OC_LS);
+ }
+
+ /* under voltage */
+ if (level_one & WM8350_UV_INT) {
+ u16 uv;
+
+ uv = wm8350_reg_read(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS);
+ uv &= ~wm8350_reg_read(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK);
+
+ if (uv & WM8350_UV_DC1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC1);
+ if (uv & WM8350_UV_DC2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC2);
+ if (uv & WM8350_UV_DC3_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC3);
+ if (uv & WM8350_UV_DC4_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC4);
+ if (uv & WM8350_UV_DC5_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC5);
+ if (uv & WM8350_UV_DC6_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_DC6);
+ if (uv & WM8350_UV_LDO1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO1);
+ if (uv & WM8350_UV_LDO2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO2);
+ if (uv & WM8350_UV_LDO3_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO3);
+ if (uv & WM8350_UV_LDO4_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_UV_LDO4);
+ }
+
+ /* charger, RTC */
+ if (status1) {
+ if (status1 & WM8350_CHG_BAT_HOT_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_HOT);
+ if (status1 & WM8350_CHG_BAT_COLD_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_COLD);
+ if (status1 & WM8350_CHG_BAT_FAIL_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_BAT_FAIL);
+ if (status1 & WM8350_CHG_TO_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_TO);
+ if (status1 & WM8350_CHG_END_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_END);
+ if (status1 & WM8350_CHG_START_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CHG_START);
+ if (status1 & WM8350_CHG_FAST_RDY_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_FAST_RDY);
+ if (status1 & WM8350_CHG_VBATT_LT_3P9_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_3P9);
+ if (status1 & WM8350_CHG_VBATT_LT_3P1_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_3P1);
+ if (status1 & WM8350_CHG_VBATT_LT_2P85_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CHG_VBATT_LT_2P85);
+ if (status1 & WM8350_RTC_ALM_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_ALM);
+ if (status1 & WM8350_RTC_SEC_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_SEC);
+ if (status1 & WM8350_RTC_PER_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_RTC_PER);
+ }
+
+ /* current sink, system, aux adc */
+ if (status2) {
+ if (status2 & WM8350_CS1_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS1);
+ if (status2 & WM8350_CS2_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CS2);
+
+ if (status2 & WM8350_SYS_HYST_COMP_FAIL_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_HYST_COMP_FAIL);
+ if (status2 & WM8350_SYS_CHIP_GT115_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_CHIP_GT115);
+ if (status2 & WM8350_SYS_CHIP_GT140_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_CHIP_GT140);
+ if (status2 & WM8350_SYS_WDOG_TO_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_SYS_WDOG_TO);
+
+ if (status2 & WM8350_AUXADC_DATARDY_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DATARDY);
+ if (status2 & WM8350_AUXADC_DCOMP4_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP4);
+ if (status2 & WM8350_AUXADC_DCOMP3_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP3);
+ if (status2 & WM8350_AUXADC_DCOMP2_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP2);
+ if (status2 & WM8350_AUXADC_DCOMP1_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_AUXADC_DCOMP1);
+
+ if (status2 & WM8350_USB_LIMIT_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_USB_LIMIT);
+ }
+
+ /* wake, codec, ext */
+ if (comp) {
+ if (comp & WM8350_WKUP_OFF_STATE_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_OFF_STATE);
+ if (comp & WM8350_WKUP_HIB_STATE_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_HIB_STATE);
+ if (comp & WM8350_WKUP_CONV_FAULT_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_CONV_FAULT);
+ if (comp & WM8350_WKUP_WDOG_RST_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_WDOG_RST);
+ if (comp & WM8350_WKUP_GP_PWR_ON_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_GP_PWR_ON);
+ if (comp & WM8350_WKUP_ONKEY_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_WKUP_ONKEY);
+ if (comp & WM8350_WKUP_GP_WAKEUP_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_WKUP_GP_WAKEUP);
+
+ if (comp & WM8350_CODEC_JCK_DET_L_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_JCK_DET_L);
+ if (comp & WM8350_CODEC_JCK_DET_R_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_JCK_DET_R);
+ if (comp & WM8350_CODEC_MICSCD_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_CODEC_MICSCD);
+ if (comp & WM8350_CODEC_MICD_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_CODEC_MICD);
+
+ if (comp & WM8350_EXT_USB_FB_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_USB_FB);
+ if (comp & WM8350_EXT_WALL_FB_EINT)
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_EXT_WALL_FB);
+ if (comp & WM8350_EXT_BAT_FB_EINT)
+ wm8350_irq_call_handler(wm8350, WM8350_IRQ_EXT_BAT_FB);
+ }
+
+ if (level_one & WM8350_GP_INT) {
+ int i;
+ u16 gpio;
+
+ gpio = wm8350_reg_read(wm8350, WM8350_GPIO_INT_STATUS);
+ gpio &= ~wm8350_reg_read(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK);
+
+ for (i = 0; i < 12; i++) {
+ if (gpio & (1 << i))
+ wm8350_irq_call_handler(wm8350,
+ WM8350_IRQ_GPIO(i));
+ }
+ }
+
+ enable_irq(wm8350->chip_irq);
+}
+
+static irqreturn_t wm8350_irq(int irq, void *data)
+{
+ struct wm8350 *wm8350 = data;
+
+ disable_irq_nosync(irq);
+ schedule_work(&wm8350->irq_work);
+
+ return IRQ_HANDLED;
+}
+
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+ void (*handler) (struct wm8350 *, int, void *),
+ void *data)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ || !handler)
+ return -EINVAL;
+
+ if (wm8350->irq[irq].handler)
+ return -EBUSY;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = handler;
+ wm8350->irq[irq].data = data;
+ mutex_unlock(&wm8350->irq_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_irq);
+
+int wm8350_free_irq(struct wm8350 *wm8350, int irq)
+{
+ if (irq < 0 || irq > WM8350_NUM_IRQ)
+ return -EINVAL;
+
+ mutex_lock(&wm8350->irq_mutex);
+ wm8350->irq[irq].handler = NULL;
+ mutex_unlock(&wm8350->irq_mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_free_irq);
+
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq)
+{
+ switch (irq) {
+ case WM8350_IRQ_CHG_BAT_HOT:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_HOT_EINT);
+ case WM8350_IRQ_CHG_BAT_COLD:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_COLD_EINT);
+ case WM8350_IRQ_CHG_BAT_FAIL:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_FAIL_EINT);
+ case WM8350_IRQ_CHG_TO:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_TO_EINT);
+ case WM8350_IRQ_CHG_END:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_END_EINT);
+ case WM8350_IRQ_CHG_START:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_START_EINT);
+ case WM8350_IRQ_CHG_FAST_RDY:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_FAST_RDY_EINT);
+ case WM8350_IRQ_RTC_PER:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_PER_EINT);
+ case WM8350_IRQ_RTC_SEC:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_SEC_EINT);
+ case WM8350_IRQ_RTC_ALM:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_ALM_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P9:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_2P85:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+ case WM8350_IRQ_CS1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS1_EINT);
+ case WM8350_IRQ_CS2:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS2_EINT);
+ case WM8350_IRQ_USB_LIMIT:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_USB_LIMIT_EINT);
+ case WM8350_IRQ_AUXADC_DATARDY:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DATARDY_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP4:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP4_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP3:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP3_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP2:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP2_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP1:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP1_EINT);
+ case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT115:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT115_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT140:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT140_EINT);
+ case WM8350_IRQ_SYS_WDOG_TO:
+ return wm8350_set_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_WDOG_TO_EINT);
+ case WM8350_IRQ_UV_LDO4:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO4_EINT);
+ case WM8350_IRQ_UV_LDO3:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO3_EINT);
+ case WM8350_IRQ_UV_LDO2:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO2_EINT);
+ case WM8350_IRQ_UV_LDO1:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO1_EINT);
+ case WM8350_IRQ_UV_DC6:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC6_EINT);
+ case WM8350_IRQ_UV_DC5:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC5_EINT);
+ case WM8350_IRQ_UV_DC4:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC4_EINT);
+ case WM8350_IRQ_UV_DC3:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC3_EINT);
+ case WM8350_IRQ_UV_DC2:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC2_EINT);
+ case WM8350_IRQ_UV_DC1:
+ return wm8350_set_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC1_EINT);
+ case WM8350_IRQ_OC_LS:
+ return wm8350_set_bits(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK,
+ WM8350_IM_OC_LS_EINT);
+ case WM8350_IRQ_EXT_USB_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_USB_FB_EINT);
+ case WM8350_IRQ_EXT_WALL_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_WALL_FB_EINT);
+ case WM8350_IRQ_EXT_BAT_FB:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_BAT_FB_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_L:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_L_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_R:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_R_EINT);
+ case WM8350_IRQ_CODEC_MICSCD:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICSCD_EINT);
+ case WM8350_IRQ_CODEC_MICD:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICD_EINT);
+ case WM8350_IRQ_WKUP_OFF_STATE:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_HIB_STATE:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_HIB_STATE_EINT);
+ case WM8350_IRQ_WKUP_CONV_FAULT:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_CONV_FAULT_EINT);
+ case WM8350_IRQ_WKUP_WDOG_RST:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_GP_PWR_ON:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_PWR_ON_EINT);
+ case WM8350_IRQ_WKUP_ONKEY:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_ONKEY_EINT);
+ case WM8350_IRQ_WKUP_GP_WAKEUP:
+ return wm8350_set_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_WAKEUP_EINT);
+ case WM8350_IRQ_GPIO(0):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP0_EINT);
+ case WM8350_IRQ_GPIO(1):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP1_EINT);
+ case WM8350_IRQ_GPIO(2):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP2_EINT);
+ case WM8350_IRQ_GPIO(3):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP3_EINT);
+ case WM8350_IRQ_GPIO(4):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP4_EINT);
+ case WM8350_IRQ_GPIO(5):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP5_EINT);
+ case WM8350_IRQ_GPIO(6):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP6_EINT);
+ case WM8350_IRQ_GPIO(7):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP7_EINT);
+ case WM8350_IRQ_GPIO(8):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP8_EINT);
+ case WM8350_IRQ_GPIO(9):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP9_EINT);
+ case WM8350_IRQ_GPIO(10):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP10_EINT);
+ case WM8350_IRQ_GPIO(11):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP11_EINT);
+ case WM8350_IRQ_GPIO(12):
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP12_EINT);
+ default:
+ dev_warn(wm8350->dev, "Attempting to mask unknown IRQ %d\n",
+ irq);
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_mask_irq);
+
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq)
+{
+ switch (irq) {
+ case WM8350_IRQ_CHG_BAT_HOT:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_HOT_EINT);
+ case WM8350_IRQ_CHG_BAT_COLD:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_COLD_EINT);
+ case WM8350_IRQ_CHG_BAT_FAIL:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_BAT_FAIL_EINT);
+ case WM8350_IRQ_CHG_TO:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_TO_EINT);
+ case WM8350_IRQ_CHG_END:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_END_EINT);
+ case WM8350_IRQ_CHG_START:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_START_EINT);
+ case WM8350_IRQ_CHG_FAST_RDY:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_FAST_RDY_EINT);
+ case WM8350_IRQ_RTC_PER:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_PER_EINT);
+ case WM8350_IRQ_RTC_SEC:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_SEC_EINT);
+ case WM8350_IRQ_RTC_ALM:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_RTC_ALM_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P9:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P9_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_3P1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_3P1_EINT);
+ case WM8350_IRQ_CHG_VBATT_LT_2P85:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_1_MASK,
+ WM8350_IM_CHG_VBATT_LT_2P85_EINT);
+ case WM8350_IRQ_CS1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS1_EINT);
+ case WM8350_IRQ_CS2:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_CS2_EINT);
+ case WM8350_IRQ_USB_LIMIT:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_USB_LIMIT_EINT);
+ case WM8350_IRQ_AUXADC_DATARDY:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DATARDY_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP4:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP4_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP3:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP3_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP2:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP2_EINT);
+ case WM8350_IRQ_AUXADC_DCOMP1:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_AUXADC_DCOMP1_EINT);
+ case WM8350_IRQ_SYS_HYST_COMP_FAIL:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_HYST_COMP_FAIL_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT115:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT115_EINT);
+ case WM8350_IRQ_SYS_CHIP_GT140:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_CHIP_GT140_EINT);
+ case WM8350_IRQ_SYS_WDOG_TO:
+ return wm8350_clear_bits(wm8350, WM8350_INT_STATUS_2_MASK,
+ WM8350_IM_SYS_WDOG_TO_EINT);
+ case WM8350_IRQ_UV_LDO4:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO4_EINT);
+ case WM8350_IRQ_UV_LDO3:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO3_EINT);
+ case WM8350_IRQ_UV_LDO2:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO2_EINT);
+ case WM8350_IRQ_UV_LDO1:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_LDO1_EINT);
+ case WM8350_IRQ_UV_DC6:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC6_EINT);
+ case WM8350_IRQ_UV_DC5:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC5_EINT);
+ case WM8350_IRQ_UV_DC4:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC4_EINT);
+ case WM8350_IRQ_UV_DC3:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC3_EINT);
+ case WM8350_IRQ_UV_DC2:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC2_EINT);
+ case WM8350_IRQ_UV_DC1:
+ return wm8350_clear_bits(wm8350,
+ WM8350_UNDER_VOLTAGE_INT_STATUS_MASK,
+ WM8350_IM_UV_DC1_EINT);
+ case WM8350_IRQ_OC_LS:
+ return wm8350_clear_bits(wm8350,
+ WM8350_OVER_CURRENT_INT_STATUS_MASK,
+ WM8350_IM_OC_LS_EINT);
+ case WM8350_IRQ_EXT_USB_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_USB_FB_EINT);
+ case WM8350_IRQ_EXT_WALL_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_WALL_FB_EINT);
+ case WM8350_IRQ_EXT_BAT_FB:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_EXT_BAT_FB_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_L:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_L_EINT);
+ case WM8350_IRQ_CODEC_JCK_DET_R:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_JCK_DET_R_EINT);
+ case WM8350_IRQ_CODEC_MICSCD:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICSCD_EINT);
+ case WM8350_IRQ_CODEC_MICD:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_CODEC_MICD_EINT);
+ case WM8350_IRQ_WKUP_OFF_STATE:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_HIB_STATE:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_HIB_STATE_EINT);
+ case WM8350_IRQ_WKUP_CONV_FAULT:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_CONV_FAULT_EINT);
+ case WM8350_IRQ_WKUP_WDOG_RST:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_OFF_STATE_EINT);
+ case WM8350_IRQ_WKUP_GP_PWR_ON:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_PWR_ON_EINT);
+ case WM8350_IRQ_WKUP_ONKEY:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_ONKEY_EINT);
+ case WM8350_IRQ_WKUP_GP_WAKEUP:
+ return wm8350_clear_bits(wm8350,
+ WM8350_COMPARATOR_INT_STATUS_MASK,
+ WM8350_IM_WKUP_GP_WAKEUP_EINT);
+ case WM8350_IRQ_GPIO(0):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP0_EINT);
+ case WM8350_IRQ_GPIO(1):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP1_EINT);
+ case WM8350_IRQ_GPIO(2):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP2_EINT);
+ case WM8350_IRQ_GPIO(3):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP3_EINT);
+ case WM8350_IRQ_GPIO(4):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP4_EINT);
+ case WM8350_IRQ_GPIO(5):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP5_EINT);
+ case WM8350_IRQ_GPIO(6):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP6_EINT);
+ case WM8350_IRQ_GPIO(7):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP7_EINT);
+ case WM8350_IRQ_GPIO(8):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP8_EINT);
+ case WM8350_IRQ_GPIO(9):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP9_EINT);
+ case WM8350_IRQ_GPIO(10):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP10_EINT);
+ case WM8350_IRQ_GPIO(11):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP11_EINT);
+ case WM8350_IRQ_GPIO(12):
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_STATUS_MASK,
+ WM8350_IM_GP12_EINT);
+ default:
+ dev_warn(wm8350->dev, "Attempting to unmask unknown IRQ %d\n",
+ irq);
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_unmask_irq);
+
+/*
+ * Cache is always host endian.
+ */
+static int wm8350_create_cache(struct wm8350 *wm8350, int mode)
+{
+ int i, ret = 0;
+ u16 value;
+ const u16 *reg_map;
+
+ switch (mode) {
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+ case 0:
+ reg_map = wm8350_mode0_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+ case 1:
+ reg_map = wm8350_mode1_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+ case 2:
+ reg_map = wm8350_mode2_defaults;
+ break;
+#endif
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+ case 3:
+ reg_map = wm8350_mode3_defaults;
+ break;
+#endif
+ default:
+ dev_err(wm8350->dev, "Configuration mode %d not supported\n",
+ mode);
+ return -EINVAL;
+ }
+
+ wm8350->reg_cache =
+ kzalloc(sizeof(u16) * (WM8350_MAX_REGISTER + 1), GFP_KERNEL);
+ if (wm8350->reg_cache == NULL)
+ return -ENOMEM;
+
+ /* Read the initial cache state back from the device - this is
+ * a PMIC so the device many not be in a virgin state and we
+ * can't rely on the silicon values.
+ */
+ for (i = 0; i < WM8350_MAX_REGISTER; i++) {
+ /* audio register range */
+ if (wm8350_reg_io_map[i].readable &&
+ (i < WM8350_CLOCK_CONTROL_1 || i > WM8350_AIF_TEST)) {
+ ret = wm8350->read_dev(wm8350, i, 2, (char *)&value);
+ if (ret < 0) {
+ dev_err(wm8350->dev,
+ "failed to read initial cache value\n");
+ goto out;
+ }
+ value = be16_to_cpu(value);
+ value &= wm8350_reg_io_map[i].readable;
+ wm8350->reg_cache[i] = value;
+ } else
+ wm8350->reg_cache[i] = reg_map[i];
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_create_cache);
+
+/*
+ * Register a client device. This is non-fatal since there is no need to
+ * fail the entire device init due to a single platform device failing.
+ */
+static void wm8350_client_dev_register(struct wm8350 *wm8350,
+ const char *name,
+ struct platform_device **pdev)
+{
+ int ret;
+
+ *pdev = platform_device_alloc(name, -1);
+ if (pdev == NULL) {
+ dev_err(wm8350->dev, "Failed to allocate %s\n", name);
+ return;
+ }
+
+ (*pdev)->dev.parent = wm8350->dev;
+ platform_set_drvdata(*pdev, wm8350);
+ ret = platform_device_add(*pdev);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to register %s: %d\n", name, ret);
+ platform_device_put(*pdev);
+ *pdev = NULL;
+ }
+}
+
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+ struct wm8350_platform_data *pdata)
+{
+ int ret = -EINVAL;
+ u16 id1, id2, mask, mode;
+
+ /* get WM8350 revision and config mode */
+ wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
+ wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+
+ id1 = be16_to_cpu(id1);
+ id2 = be16_to_cpu(id2);
+
+ if (id1 == 0x6143) {
+ switch ((id2 & WM8350_CHIP_REV_MASK) >> 12) {
+ case WM8350_REV_E:
+ dev_info(wm8350->dev, "Found Rev E device\n");
+ wm8350->rev = WM8350_REV_E;
+ break;
+ case WM8350_REV_F:
+ dev_info(wm8350->dev, "Found Rev F device\n");
+ wm8350->rev = WM8350_REV_F;
+ break;
+ case WM8350_REV_G:
+ dev_info(wm8350->dev, "Found Rev G device\n");
+ wm8350->rev = WM8350_REV_G;
+ break;
+ default:
+ /* For safety we refuse to run on unknown hardware */
+ dev_info(wm8350->dev, "Found unknown rev\n");
+ ret = -ENODEV;
+ goto err;
+ }
+ } else {
+ dev_info(wm8350->dev, "Device with ID %x is not a WM8350\n",
+ id1);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ mode = id2 & WM8350_CONF_STS_MASK >> 10;
+ mask = id2 & WM8350_CUST_ID_MASK;
+ dev_info(wm8350->dev, "Config mode %d, ROM mask %d\n", mode, mask);
+
+ ret = wm8350_create_cache(wm8350, mode);
+ if (ret < 0) {
+ printk(KERN_ERR "wm8350: failed to create register cache\n");
+ return ret;
+ }
+
+ if (pdata->init) {
+ ret = pdata->init(wm8350);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Platform init() failed: %d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ mutex_init(&wm8350->irq_mutex);
+ INIT_WORK(&wm8350->irq_work, wm8350_irq_worker);
+ if (irq != NO_IRQ) {
+ ret = request_irq(irq, wm8350_irq, 0,
+ "wm8350", wm8350);
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to request IRQ: %d\n",
+ ret);
+ goto err;
+ }
+ } else {
+ dev_err(wm8350->dev, "No IRQ configured\n");
+ goto err;
+ }
+ wm8350->chip_irq = irq;
+
+ wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
+
+ wm8350_client_dev_register(wm8350, "wm8350-codec",
+ &(wm8350->codec.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-gpio",
+ &(wm8350->gpio.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-power",
+ &(wm8350->power.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-rtc", &(wm8350->rtc.pdev));
+ wm8350_client_dev_register(wm8350, "wm8350-wdt", &(wm8350->wdt.pdev));
+
+ return 0;
+
+err:
+ kfree(wm8350->reg_cache);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_device_init);
+
+void wm8350_device_exit(struct wm8350 *wm8350)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++)
+ platform_device_unregister(wm8350->pmic.pdev[i]);
+
+ platform_device_unregister(wm8350->wdt.pdev);
+ platform_device_unregister(wm8350->rtc.pdev);
+ platform_device_unregister(wm8350->power.pdev);
+ platform_device_unregister(wm8350->gpio.pdev);
+ platform_device_unregister(wm8350->codec.pdev);
+
+ free_irq(wm8350->chip_irq, wm8350);
+ flush_work(&wm8350->irq_work);
+ kfree(wm8350->reg_cache);
+}
+EXPORT_SYMBOL_GPL(wm8350_device_exit);
+
+MODULE_DESCRIPTION("WM8350 AudioPlus PMIC core driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-gpio.c b/drivers/mfd/wm8350-gpio.c
new file mode 100644
index 00000000000..ebf99bef392
--- /dev/null
+++ b/drivers/mfd/wm8350-gpio.c
@@ -0,0 +1,222 @@
+/*
+ * wm8350-core.c -- Device access for Wolfson WM8350
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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/module.h>
+#include <linux/errno.h>
+
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+
+static int gpio_set_dir(struct wm8350 *wm8350, int gpio, int dir)
+{
+ int ret;
+
+ wm8350_reg_unlock(wm8350);
+ if (dir == WM8350_GPIO_DIR_OUT)
+ ret = wm8350_clear_bits(wm8350,
+ WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << gpio);
+ else
+ ret = wm8350_set_bits(wm8350,
+ WM8350_GPIO_CONFIGURATION_I_O,
+ 1 << gpio);
+ wm8350_reg_lock(wm8350);
+ return ret;
+}
+
+static int gpio_set_debounce(struct wm8350 *wm8350, int gpio, int db)
+{
+ if (db == WM8350_GPIO_DEBOUNCE_ON)
+ return wm8350_set_bits(wm8350, WM8350_GPIO_DEBOUNCE,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_DEBOUNCE, 1 << gpio);
+}
+
+static int gpio_set_func(struct wm8350 *wm8350, int gpio, int func)
+{
+ u16 reg;
+
+ wm8350_reg_unlock(wm8350);
+ switch (gpio) {
+ case 0:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP0_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 1:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP1_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 2:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP2_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 3:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_1)
+ & ~WM8350_GP3_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_1,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 4:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP4_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 5:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP5_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 6:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP6_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 7:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_2)
+ & ~WM8350_GP7_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_2,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 8:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP8_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 0));
+ break;
+ case 9:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP9_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 4));
+ break;
+ case 10:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP10_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 8));
+ break;
+ case 11:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_3)
+ & ~WM8350_GP11_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_3,
+ reg | ((func & 0xf) << 12));
+ break;
+ case 12:
+ reg = wm8350_reg_read(wm8350, WM8350_GPIO_FUNCTION_SELECT_4)
+ & ~WM8350_GP12_FN_MASK;
+ wm8350_reg_write(wm8350, WM8350_GPIO_FUNCTION_SELECT_4,
+ reg | ((func & 0xf) << 0));
+ break;
+ default:
+ wm8350_reg_lock(wm8350);
+ return -EINVAL;
+ }
+
+ wm8350_reg_lock(wm8350);
+ return 0;
+}
+
+static int gpio_set_pull_up(struct wm8350 *wm8350, int gpio, int up)
+{
+ if (up)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PIN_PULL_UP_CONTROL,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PIN_PULL_UP_CONTROL,
+ 1 << gpio);
+}
+
+static int gpio_set_pull_down(struct wm8350 *wm8350, int gpio, int down)
+{
+ if (down)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PULL_DOWN_CONTROL,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PULL_DOWN_CONTROL,
+ 1 << gpio);
+}
+
+static int gpio_set_polarity(struct wm8350 *wm8350, int gpio, int pol)
+{
+ if (pol == WM8350_GPIO_ACTIVE_HIGH)
+ return wm8350_set_bits(wm8350,
+ WM8350_GPIO_PIN_POLARITY_TYPE,
+ 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_PIN_POLARITY_TYPE,
+ 1 << gpio);
+}
+
+static int gpio_set_invert(struct wm8350 *wm8350, int gpio, int invert)
+{
+ if (invert == WM8350_GPIO_INVERT_ON)
+ return wm8350_set_bits(wm8350, WM8350_GPIO_INT_MODE, 1 << gpio);
+ else
+ return wm8350_clear_bits(wm8350,
+ WM8350_GPIO_INT_MODE, 1 << gpio);
+}
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+ int pol, int pull, int invert, int debounce)
+{
+ /* make sure we never pull up and down at the same time */
+ if (pull == WM8350_GPIO_PULL_NONE) {
+ if (gpio_set_pull_up(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_down(wm8350, gpio, 0))
+ goto err;
+ } else if (pull == WM8350_GPIO_PULL_UP) {
+ if (gpio_set_pull_down(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_up(wm8350, gpio, 1))
+ goto err;
+ } else if (pull == WM8350_GPIO_PULL_DOWN) {
+ if (gpio_set_pull_up(wm8350, gpio, 0))
+ goto err;
+ if (gpio_set_pull_down(wm8350, gpio, 1))
+ goto err;
+ }
+
+ if (gpio_set_invert(wm8350, gpio, invert))
+ goto err;
+ if (gpio_set_polarity(wm8350, gpio, pol))
+ goto err;
+ if (gpio_set_debounce(wm8350, gpio, debounce))
+ goto err;
+ if (gpio_set_dir(wm8350, gpio, dir))
+ goto err;
+ return gpio_set_func(wm8350, gpio, func);
+
+err:
+ return -EIO;
+}
+EXPORT_SYMBOL_GPL(wm8350_gpio_config);
diff --git a/drivers/mfd/wm8350-i2c.c b/drivers/mfd/wm8350-i2c.c
new file mode 100644
index 00000000000..8dfe21bb3bd
--- /dev/null
+++ b/drivers/mfd/wm8350-i2c.c
@@ -0,0 +1,120 @@
+/*
+ * wm8350-i2c.c -- Generic I2C driver for Wolfson WM8350 PMIC
+ *
+ * This driver defines and configures the WM8350 for the Freescale i.MX32ADS.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ * linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/wm8350/core.h>
+
+static int wm8350_i2c_read_device(struct wm8350 *wm8350, char reg,
+ int bytes, void *dest)
+{
+ int ret;
+
+ ret = i2c_master_send(wm8350->i2c_client, &reg, 1);
+ if (ret < 0)
+ return ret;
+ return i2c_master_recv(wm8350->i2c_client, dest, bytes);
+}
+
+static int wm8350_i2c_write_device(struct wm8350 *wm8350, char reg,
+ int bytes, void *src)
+{
+ /* we add 1 byte for device register */
+ u8 msg[(WM8350_MAX_REGISTER << 1) + 1];
+
+ if (bytes > ((WM8350_MAX_REGISTER << 1) + 1))
+ return -EINVAL;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, bytes);
+ return i2c_master_send(wm8350->i2c_client, msg, bytes + 1);
+}
+
+static int wm8350_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8350 *wm8350;
+ int ret = 0;
+
+ wm8350 = kzalloc(sizeof(struct wm8350), GFP_KERNEL);
+ if (wm8350 == NULL) {
+ kfree(i2c);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(i2c, wm8350);
+ wm8350->dev = &i2c->dev;
+ wm8350->i2c_client = i2c;
+ wm8350->read_dev = wm8350_i2c_read_device;
+ wm8350->write_dev = wm8350_i2c_write_device;
+
+ ret = wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
+ if (ret < 0)
+ goto err;
+
+ return ret;
+
+err:
+ kfree(wm8350);
+ return ret;
+}
+
+static int wm8350_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm8350 *wm8350 = i2c_get_clientdata(i2c);
+
+ wm8350_device_exit(wm8350);
+ kfree(wm8350);
+
+ return 0;
+}
+
+static const struct i2c_device_id wm8350_i2c_id[] = {
+ { "wm8350", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8350_i2c_id);
+
+
+static struct i2c_driver wm8350_i2c_driver = {
+ .driver = {
+ .name = "wm8350",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8350_i2c_probe,
+ .remove = wm8350_i2c_remove,
+ .id_table = wm8350_i2c_id,
+};
+
+static int __init wm8350_i2c_init(void)
+{
+ return i2c_add_driver(&wm8350_i2c_driver);
+}
+/* init early so consumer devices can complete system boot */
+subsys_initcall(wm8350_i2c_init);
+
+static void __exit wm8350_i2c_exit(void)
+{
+ i2c_del_driver(&wm8350_i2c_driver);
+}
+module_exit(wm8350_i2c_exit);
+
+MODULE_DESCRIPTION("I2C support for the WM8350 AudioPlus PMIC");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/wm8350-regmap.c b/drivers/mfd/wm8350-regmap.c
new file mode 100644
index 00000000000..974678db22c
--- /dev/null
+++ b/drivers/mfd/wm8350-regmap.c
@@ -0,0 +1,1347 @@
+/*
+ * wm8350-regmap.c -- Wolfson Microelectronics WM8350 register map
+ *
+ * This file splits out the tables describing the defaults and access
+ * status of the WM8350 registers since they are rather large.
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * 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/mfd/wm8350/core.h>
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_0
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode0_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* R3 - System Control 1 */
+ 0x0004, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 - Power Up Interrupt Status */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 - Power Up Interrupt Status Mask */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3B00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 - AIF Test */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0FFC, /* R134 - GPIO Configuration (i/o) */
+ 0x0FFC, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0013, /* R140 - GPIO Function Select 1 */
+ 0x0000, /* R141 - GPIO Function Select 2 */
+ 0x0000, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x002D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0000, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0000, /* R186 - DCDC3 Control */
+ 0x0000, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0000, /* R189 - DCDC4 Control */
+ 0x0000, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0000, /* R195 - DCDC6 Control */
+ 0x0000, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x001B, /* R203 - LDO2 Control */
+ 0x0000, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001B, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001B, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_1
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode1_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* R3 - System Control 1 */
+ 0x0014, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 - Power Up Interrupt Status */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 - Power Up Interrupt Status Mask */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3B00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 - AIF Test */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x00FB, /* R134 - GPIO Configuration (i/o) */
+ 0x04FE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0312, /* R140 - GPIO Function Select 1 */
+ 0x1003, /* R141 - GPIO Function Select 2 */
+ 0x1331, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x002D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x0062, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x0026, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0062, /* R189 - DCDC4 Control */
+ 0x0400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0800, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x0006, /* R200 - LDO1 Control */
+ 0x0400, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0006, /* R203 - LDO2 Control */
+ 0x0400, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001B, /* R206 - LDO3 Control */
+ 0x0000, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001B, /* R209 - LDO4 Control */
+ 0x0000, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_2
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode2_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1002, /* R3 - System Control 1 */
+ 0x0014, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 - Power Up Interrupt Status */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 - Power Up Interrupt Status Mask */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3B00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 - AIF Test */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x08FB, /* R134 - GPIO Configuration (i/o) */
+ 0x0CFE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x0312, /* R140 - GPIO Function Select 1 */
+ 0x0003, /* R141 - GPIO Function Select 2 */
+ 0x2331, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x002D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x002E, /* R186 - DCDC3 Control */
+ 0x0800, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x000E, /* R189 - DCDC4 Control */
+ 0x0800, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0C00, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001A, /* R200 - LDO1 Control */
+ 0x0800, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x0010, /* R203 - LDO2 Control */
+ 0x0800, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x000A, /* R206 - LDO3 Control */
+ 0x0C00, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001A, /* R209 - LDO4 Control */
+ 0x0800, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+#ifdef CONFIG_MFD_WM8350_CONFIG_MODE_3
+
+#undef WM8350_HAVE_CONFIG_MODE
+#define WM8350_HAVE_CONFIG_MODE
+
+const u16 wm8350_mode3_defaults[] = {
+ 0x17FF, /* R0 - Reset/ID */
+ 0x1000, /* R1 - ID */
+ 0x0000, /* R2 */
+ 0x1000, /* R3 - System Control 1 */
+ 0x0004, /* R4 - System Control 2 */
+ 0x0000, /* R5 - System Hibernate */
+ 0x8A00, /* R6 - Interface Control */
+ 0x0000, /* R7 */
+ 0x8000, /* R8 - Power mgmt (1) */
+ 0x0000, /* R9 - Power mgmt (2) */
+ 0x0000, /* R10 - Power mgmt (3) */
+ 0x2000, /* R11 - Power mgmt (4) */
+ 0x0E00, /* R12 - Power mgmt (5) */
+ 0x0000, /* R13 - Power mgmt (6) */
+ 0x0000, /* R14 - Power mgmt (7) */
+ 0x0000, /* R15 */
+ 0x0000, /* R16 - RTC Seconds/Minutes */
+ 0x0100, /* R17 - RTC Hours/Day */
+ 0x0101, /* R18 - RTC Date/Month */
+ 0x1400, /* R19 - RTC Year */
+ 0x0000, /* R20 - Alarm Seconds/Minutes */
+ 0x0000, /* R21 - Alarm Hours/Day */
+ 0x0000, /* R22 - Alarm Date/Month */
+ 0x0320, /* R23 - RTC Time Control */
+ 0x0000, /* R24 - System Interrupts */
+ 0x0000, /* R25 - Interrupt Status 1 */
+ 0x0000, /* R26 - Interrupt Status 2 */
+ 0x0000, /* R27 - Power Up Interrupt Status */
+ 0x0000, /* R28 - Under Voltage Interrupt status */
+ 0x0000, /* R29 - Over Current Interrupt status */
+ 0x0000, /* R30 - GPIO Interrupt Status */
+ 0x0000, /* R31 - Comparator Interrupt Status */
+ 0x3FFF, /* R32 - System Interrupts Mask */
+ 0x0000, /* R33 - Interrupt Status 1 Mask */
+ 0x0000, /* R34 - Interrupt Status 2 Mask */
+ 0x0000, /* R35 - Power Up Interrupt Status Mask */
+ 0x0000, /* R36 - Under Voltage Interrupt status Mask */
+ 0x0000, /* R37 - Over Current Interrupt status Mask */
+ 0x0000, /* R38 - GPIO Interrupt Status Mask */
+ 0x0000, /* R39 - Comparator Interrupt Status Mask */
+ 0x0040, /* R40 - Clock Control 1 */
+ 0x0000, /* R41 - Clock Control 2 */
+ 0x3B00, /* R42 - FLL Control 1 */
+ 0x7086, /* R43 - FLL Control 2 */
+ 0xC226, /* R44 - FLL Control 3 */
+ 0x0000, /* R45 - FLL Control 4 */
+ 0x0000, /* R46 */
+ 0x0000, /* R47 */
+ 0x0000, /* R48 - DAC Control */
+ 0x0000, /* R49 */
+ 0x00C0, /* R50 - DAC Digital Volume L */
+ 0x00C0, /* R51 - DAC Digital Volume R */
+ 0x0000, /* R52 */
+ 0x0040, /* R53 - DAC LR Rate */
+ 0x0000, /* R54 - DAC Clock Control */
+ 0x0000, /* R55 */
+ 0x0000, /* R56 */
+ 0x0000, /* R57 */
+ 0x4000, /* R58 - DAC Mute */
+ 0x0000, /* R59 - DAC Mute Volume */
+ 0x0000, /* R60 - DAC Side */
+ 0x0000, /* R61 */
+ 0x0000, /* R62 */
+ 0x0000, /* R63 */
+ 0x8000, /* R64 - ADC Control */
+ 0x0000, /* R65 */
+ 0x00C0, /* R66 - ADC Digital Volume L */
+ 0x00C0, /* R67 - ADC Digital Volume R */
+ 0x0000, /* R68 - ADC Divider */
+ 0x0000, /* R69 */
+ 0x0040, /* R70 - ADC LR Rate */
+ 0x0000, /* R71 */
+ 0x0303, /* R72 - Input Control */
+ 0x0000, /* R73 - IN3 Input Control */
+ 0x0000, /* R74 - Mic Bias Control */
+ 0x0000, /* R75 */
+ 0x0000, /* R76 - Output Control */
+ 0x0000, /* R77 - Jack Detect */
+ 0x0000, /* R78 - Anti Pop Control */
+ 0x0000, /* R79 */
+ 0x0040, /* R80 - Left Input Volume */
+ 0x0040, /* R81 - Right Input Volume */
+ 0x0000, /* R82 */
+ 0x0000, /* R83 */
+ 0x0000, /* R84 */
+ 0x0000, /* R85 */
+ 0x0000, /* R86 */
+ 0x0000, /* R87 */
+ 0x0800, /* R88 - Left Mixer Control */
+ 0x1000, /* R89 - Right Mixer Control */
+ 0x0000, /* R90 */
+ 0x0000, /* R91 */
+ 0x0000, /* R92 - OUT3 Mixer Control */
+ 0x0000, /* R93 - OUT4 Mixer Control */
+ 0x0000, /* R94 */
+ 0x0000, /* R95 */
+ 0x0000, /* R96 - Output Left Mixer Volume */
+ 0x0000, /* R97 - Output Right Mixer Volume */
+ 0x0000, /* R98 - Input Mixer Volume L */
+ 0x0000, /* R99 - Input Mixer Volume R */
+ 0x0000, /* R100 - Input Mixer Volume */
+ 0x0000, /* R101 */
+ 0x0000, /* R102 */
+ 0x0000, /* R103 */
+ 0x00E4, /* R104 - LOUT1 Volume */
+ 0x00E4, /* R105 - ROUT1 Volume */
+ 0x00E4, /* R106 - LOUT2 Volume */
+ 0x02E4, /* R107 - ROUT2 Volume */
+ 0x0000, /* R108 */
+ 0x0000, /* R109 */
+ 0x0000, /* R110 */
+ 0x0000, /* R111 - BEEP Volume */
+ 0x0A00, /* R112 - AI Formating */
+ 0x0000, /* R113 - ADC DAC COMP */
+ 0x0020, /* R114 - AI ADC Control */
+ 0x0020, /* R115 - AI DAC Control */
+ 0x0000, /* R116 - AIF Test */
+ 0x0000, /* R117 */
+ 0x0000, /* R118 */
+ 0x0000, /* R119 */
+ 0x0000, /* R120 */
+ 0x0000, /* R121 */
+ 0x0000, /* R122 */
+ 0x0000, /* R123 */
+ 0x0000, /* R124 */
+ 0x0000, /* R125 */
+ 0x0000, /* R126 */
+ 0x0000, /* R127 */
+ 0x1FFF, /* R128 - GPIO Debounce */
+ 0x0000, /* R129 - GPIO Pin pull up Control */
+ 0x03FC, /* R130 - GPIO Pull down Control */
+ 0x0000, /* R131 - GPIO Interrupt Mode */
+ 0x0000, /* R132 */
+ 0x0000, /* R133 - GPIO Control */
+ 0x0A7B, /* R134 - GPIO Configuration (i/o) */
+ 0x06FE, /* R135 - GPIO Pin Polarity / Type */
+ 0x0000, /* R136 */
+ 0x0000, /* R137 */
+ 0x0000, /* R138 */
+ 0x0000, /* R139 */
+ 0x1312, /* R140 - GPIO Function Select 1 */
+ 0x1030, /* R141 - GPIO Function Select 2 */
+ 0x2231, /* R142 - GPIO Function Select 3 */
+ 0x0003, /* R143 - GPIO Function Select 4 */
+ 0x0000, /* R144 - Digitiser Control (1) */
+ 0x0002, /* R145 - Digitiser Control (2) */
+ 0x0000, /* R146 */
+ 0x0000, /* R147 */
+ 0x0000, /* R148 */
+ 0x0000, /* R149 */
+ 0x0000, /* R150 */
+ 0x0000, /* R151 */
+ 0x7000, /* R152 - AUX1 Readback */
+ 0x7000, /* R153 - AUX2 Readback */
+ 0x7000, /* R154 - AUX3 Readback */
+ 0x7000, /* R155 - AUX4 Readback */
+ 0x0000, /* R156 - USB Voltage Readback */
+ 0x0000, /* R157 - LINE Voltage Readback */
+ 0x0000, /* R158 - BATT Voltage Readback */
+ 0x0000, /* R159 - Chip Temp Readback */
+ 0x0000, /* R160 */
+ 0x0000, /* R161 */
+ 0x0000, /* R162 */
+ 0x0000, /* R163 - Generic Comparator Control */
+ 0x0000, /* R164 - Generic comparator 1 */
+ 0x0000, /* R165 - Generic comparator 2 */
+ 0x0000, /* R166 - Generic comparator 3 */
+ 0x0000, /* R167 - Generic comparator 4 */
+ 0xA00F, /* R168 - Battery Charger Control 1 */
+ 0x0B06, /* R169 - Battery Charger Control 2 */
+ 0x0000, /* R170 - Battery Charger Control 3 */
+ 0x0000, /* R171 */
+ 0x0000, /* R172 - Current Sink Driver A */
+ 0x0000, /* R173 - CSA Flash control */
+ 0x0000, /* R174 - Current Sink Driver B */
+ 0x0000, /* R175 - CSB Flash control */
+ 0x0000, /* R176 - DCDC/LDO requested */
+ 0x002D, /* R177 - DCDC Active options */
+ 0x0000, /* R178 - DCDC Sleep options */
+ 0x0025, /* R179 - Power-check comparator */
+ 0x000E, /* R180 - DCDC1 Control */
+ 0x0400, /* R181 - DCDC1 Timeouts */
+ 0x1006, /* R182 - DCDC1 Low Power */
+ 0x0018, /* R183 - DCDC2 Control */
+ 0x0000, /* R184 - DCDC2 Timeouts */
+ 0x0000, /* R185 */
+ 0x000E, /* R186 - DCDC3 Control */
+ 0x0400, /* R187 - DCDC3 Timeouts */
+ 0x0006, /* R188 - DCDC3 Low Power */
+ 0x0026, /* R189 - DCDC4 Control */
+ 0x0400, /* R190 - DCDC4 Timeouts */
+ 0x0006, /* R191 - DCDC4 Low Power */
+ 0x0008, /* R192 - DCDC5 Control */
+ 0x0000, /* R193 - DCDC5 Timeouts */
+ 0x0000, /* R194 */
+ 0x0026, /* R195 - DCDC6 Control */
+ 0x0400, /* R196 - DCDC6 Timeouts */
+ 0x0006, /* R197 - DCDC6 Low Power */
+ 0x0000, /* R198 */
+ 0x0003, /* R199 - Limit Switch Control */
+ 0x001C, /* R200 - LDO1 Control */
+ 0x0000, /* R201 - LDO1 Timeouts */
+ 0x001C, /* R202 - LDO1 Low Power */
+ 0x001C, /* R203 - LDO2 Control */
+ 0x0400, /* R204 - LDO2 Timeouts */
+ 0x001C, /* R205 - LDO2 Low Power */
+ 0x001C, /* R206 - LDO3 Control */
+ 0x0400, /* R207 - LDO3 Timeouts */
+ 0x001C, /* R208 - LDO3 Low Power */
+ 0x001F, /* R209 - LDO4 Control */
+ 0x0400, /* R210 - LDO4 Timeouts */
+ 0x001C, /* R211 - LDO4 Low Power */
+ 0x0000, /* R212 */
+ 0x0000, /* R213 */
+ 0x0000, /* R214 */
+ 0x0000, /* R215 - VCC_FAULT Masks */
+ 0x001F, /* R216 - Main Bandgap Control */
+ 0x0000, /* R217 - OSC Control */
+ 0x9000, /* R218 - RTC Tick Control */
+ 0x0000, /* R219 */
+ 0x4000, /* R220 - RAM BIST 1 */
+ 0x0000, /* R221 */
+ 0x0000, /* R222 */
+ 0x0000, /* R223 */
+ 0x0000, /* R224 */
+ 0x0000, /* R225 - DCDC/LDO status */
+ 0x0000, /* R226 */
+ 0x0000, /* R227 */
+ 0x0000, /* R228 */
+ 0x0000, /* R229 */
+ 0xE000, /* R230 - GPIO Pin Status */
+ 0x0000, /* R231 */
+ 0x0000, /* R232 */
+ 0x0000, /* R233 */
+ 0x0000, /* R234 */
+ 0x0000, /* R235 */
+ 0x0000, /* R236 */
+ 0x0000, /* R237 */
+ 0x0000, /* R238 */
+ 0x0000, /* R239 */
+ 0x0000, /* R240 */
+ 0x0000, /* R241 */
+ 0x0000, /* R242 */
+ 0x0000, /* R243 */
+ 0x0000, /* R244 */
+ 0x0000, /* R245 */
+ 0x0000, /* R246 */
+ 0x0000, /* R247 */
+ 0x0000, /* R248 */
+ 0x0000, /* R249 */
+ 0x0000, /* R250 */
+ 0x0000, /* R251 */
+ 0x0000, /* R252 */
+ 0x0000, /* R253 */
+ 0x0000, /* R254 */
+ 0x0000, /* R255 */
+};
+#endif
+
+/* The register defaults for the config mode used must be compiled in but
+ * due to the impact on kernel size it is possible to disable
+ */
+#ifndef WM8350_HAVE_CONFIG_MODE
+#warning No WM8350 config modes supported - select at least one of the
+#warning MFD_WM8350_CONFIG_MODE_n options from the board driver.
+#endif
+
+/*
+ * Access masks.
+ */
+
+const struct wm8350_reg_access wm8350_reg_io_map[] = {
+ /* read write volatile */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R0 - Reset/ID */
+ { 0x7CFF, 0x0C00, 0x7FFF }, /* R1 - ID */
+ { 0x0000, 0x0000, 0x0000 }, /* R2 */
+ { 0xBE3B, 0xBE3B, 0x8000 }, /* R3 - System Control 1 */
+ { 0xFCF7, 0xFCF7, 0xF800 }, /* R4 - System Control 2 */
+ { 0x80FF, 0x80FF, 0x8000 }, /* R5 - System Hibernate */
+ { 0xFB0E, 0xFB0E, 0x0000 }, /* R6 - Interface Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R7 */
+ { 0xE537, 0xE537, 0xFFFF }, /* R8 - Power mgmt (1) */
+ { 0x0FF3, 0x0FF3, 0xFFFF }, /* R9 - Power mgmt (2) */
+ { 0x008F, 0x008F, 0xFFFF }, /* R10 - Power mgmt (3) */
+ { 0x6D3C, 0x6D3C, 0xFFFF }, /* R11 - Power mgmt (4) */
+ { 0x1F8F, 0x1F8F, 0xFFFF }, /* R12 - Power mgmt (5) */
+ { 0x8F3F, 0x8F3F, 0xFFFF }, /* R13 - Power mgmt (6) */
+ { 0x0003, 0x0003, 0xFFFF }, /* R14 - Power mgmt (7) */
+ { 0x0000, 0x0000, 0x0000 }, /* R15 */
+ { 0x7F7F, 0x7F7F, 0xFFFF }, /* R16 - RTC Seconds/Minutes */
+ { 0x073F, 0x073F, 0xFFFF }, /* R17 - RTC Hours/Day */
+ { 0x1F3F, 0x1F3F, 0xFFFF }, /* R18 - RTC Date/Month */
+ { 0x3FFF, 0x00FF, 0xFFFF }, /* R19 - RTC Year */
+ { 0x7F7F, 0x7F7F, 0x0000 }, /* R20 - Alarm Seconds/Minutes */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R21 - Alarm Hours/Day */
+ { 0x1F3F, 0x1F3F, 0x0000 }, /* R22 - Alarm Date/Month */
+ { 0xEF7F, 0xEA7F, 0xFFFF }, /* R23 - RTC Time Control */
+ { 0x3BFF, 0x0000, 0xFFFF }, /* R24 - System Interrupts */
+ { 0xFEE7, 0x0000, 0xFFFF }, /* R25 - Interrupt Status 1 */
+ { 0x35FF, 0x0000, 0xFFFF }, /* R26 - Interrupt Status 2 */
+ { 0x0F3F, 0x0000, 0xFFFF }, /* R27 - Power Up Interrupt Status */
+ { 0x0F3F, 0x0000, 0xFFFF }, /* R28 - Under Voltage Interrupt status */
+ { 0x8000, 0x0000, 0xFFFF }, /* R29 - Over Current Interrupt status */
+ { 0x1FFF, 0x0000, 0xFFFF }, /* R30 - GPIO Interrupt Status */
+ { 0xEF7F, 0x0000, 0xFFFF }, /* R31 - Comparator Interrupt Status */
+ { 0x3FFF, 0x3FFF, 0x0000 }, /* R32 - System Interrupts Mask */
+ { 0xFEE7, 0xFEE7, 0x0000 }, /* R33 - Interrupt Status 1 Mask */
+ { 0xF5FF, 0xF5FF, 0x0000 }, /* R34 - Interrupt Status 2 Mask */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R35 - Power Up Interrupt Status Mask */
+ { 0x0F3F, 0x0F3F, 0x0000 }, /* R36 - Under Voltage Int status Mask */
+ { 0x8000, 0x8000, 0x0000 }, /* R37 - Over Current Int status Mask */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R38 - GPIO Interrupt Status Mask */
+ { 0xEF7F, 0xEF7F, 0x0000 }, /* R39 - Comparator IntStatus Mask */
+ { 0xC9F7, 0xC9F7, 0xFFFF }, /* R40 - Clock Control 1 */
+ { 0x8001, 0x8001, 0x0000 }, /* R41 - Clock Control 2 */
+ { 0xFFF7, 0xFFF7, 0xFFFF }, /* R42 - FLL Control 1 */
+ { 0xFBFF, 0xFBFF, 0x0000 }, /* R43 - FLL Control 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R44 - FLL Control 3 */
+ { 0x0033, 0x0033, 0x0000 }, /* R45 - FLL Control 4 */
+ { 0x0000, 0x0000, 0x0000 }, /* R46 */
+ { 0x0000, 0x0000, 0x0000 }, /* R47 */
+ { 0x3033, 0x3033, 0x0000 }, /* R48 - DAC Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R49 */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R50 - DAC Digital Volume L */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R51 - DAC Digital Volume R */
+ { 0x0000, 0x0000, 0x0000 }, /* R52 */
+ { 0x0FFF, 0x0FFF, 0xFFFF }, /* R53 - DAC LR Rate */
+ { 0x0017, 0x0017, 0x0000 }, /* R54 - DAC Clock Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R55 */
+ { 0x0000, 0x0000, 0x0000 }, /* R56 */
+ { 0x0000, 0x0000, 0x0000 }, /* R57 */
+ { 0x4000, 0x4000, 0x0000 }, /* R58 - DAC Mute */
+ { 0x7000, 0x7000, 0x0000 }, /* R59 - DAC Mute Volume */
+ { 0x3C00, 0x3C00, 0x0000 }, /* R60 - DAC Side */
+ { 0x0000, 0x0000, 0x0000 }, /* R61 */
+ { 0x0000, 0x0000, 0x0000 }, /* R62 */
+ { 0x0000, 0x0000, 0x0000 }, /* R63 */
+ { 0x8303, 0x8303, 0xFFFF }, /* R64 - ADC Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R65 */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R66 - ADC Digital Volume L */
+ { 0x81FF, 0x81FF, 0xFFFF }, /* R67 - ADC Digital Volume R */
+ { 0x0FFF, 0x0FFF, 0x0000 }, /* R68 - ADC Divider */
+ { 0x0000, 0x0000, 0x0000 }, /* R69 */
+ { 0x0FFF, 0x0FFF, 0xFFFF }, /* R70 - ADC LR Rate */
+ { 0x0000, 0x0000, 0x0000 }, /* R71 */
+ { 0x0707, 0x0707, 0xFFFF }, /* R72 - Input Control */
+ { 0xC0C0, 0xC0C0, 0xFFFF }, /* R73 - IN3 Input Control */
+ { 0xC09F, 0xC09F, 0xFFFF }, /* R74 - Mic Bias Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R75 */
+ { 0x0F15, 0x0F15, 0xFFFF }, /* R76 - Output Control */
+ { 0xC000, 0xC000, 0xFFFF }, /* R77 - Jack Detect */
+ { 0x03FF, 0x03FF, 0x0000 }, /* R78 - Anti Pop Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R79 */
+ { 0xE1FC, 0xE1FC, 0x8000 }, /* R80 - Left Input Volume */
+ { 0xE1FC, 0xE1FC, 0x8000 }, /* R81 - Right Input Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000, 0x0000 }, /* R83 */
+ { 0x0000, 0x0000, 0x0000 }, /* R84 */
+ { 0x0000, 0x0000, 0x0000 }, /* R85 */
+ { 0x0000, 0x0000, 0x0000 }, /* R86 */
+ { 0x0000, 0x0000, 0x0000 }, /* R87 */
+ { 0x9807, 0x9807, 0xFFFF }, /* R88 - Left Mixer Control */
+ { 0x980B, 0x980B, 0xFFFF }, /* R89 - Right Mixer Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R90 */
+ { 0x0000, 0x0000, 0x0000 }, /* R91 */
+ { 0x8909, 0x8909, 0xFFFF }, /* R92 - OUT3 Mixer Control */
+ { 0x9E07, 0x9E07, 0xFFFF }, /* R93 - OUT4 Mixer Control */
+ { 0x0000, 0x0000, 0x0000 }, /* R94 */
+ { 0x0000, 0x0000, 0x0000 }, /* R95 */
+ { 0x0EEE, 0x0EEE, 0x0000 }, /* R96 - Output Left Mixer Volume */
+ { 0xE0EE, 0xE0EE, 0x0000 }, /* R97 - Output Right Mixer Volume */
+ { 0x0E0F, 0x0E0F, 0x0000 }, /* R98 - Input Mixer Volume L */
+ { 0xE0E1, 0xE0E1, 0x0000 }, /* R99 - Input Mixer Volume R */
+ { 0x800E, 0x800E, 0x0000 }, /* R100 - Input Mixer Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R101 */
+ { 0x0000, 0x0000, 0x0000 }, /* R102 */
+ { 0x0000, 0x0000, 0x0000 }, /* R103 */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R104 - LOUT1 Volume */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R105 - ROUT1 Volume */
+ { 0xE1FC, 0xE1FC, 0xFFFF }, /* R106 - LOUT2 Volume */
+ { 0xE7FC, 0xE7FC, 0xFFFF }, /* R107 - ROUT2 Volume */
+ { 0x0000, 0x0000, 0x0000 }, /* R108 */
+ { 0x0000, 0x0000, 0x0000 }, /* R109 */
+ { 0x0000, 0x0000, 0x0000 }, /* R110 */
+ { 0x80E0, 0x80E0, 0xFFFF }, /* R111 - BEEP Volume */
+ { 0xBF00, 0xBF00, 0x0000 }, /* R112 - AI Formating */
+ { 0x00F1, 0x00F1, 0x0000 }, /* R113 - ADC DAC COMP */
+ { 0x00F8, 0x00F8, 0x0000 }, /* R114 - AI ADC Control */
+ { 0x40FB, 0x40FB, 0x0000 }, /* R115 - AI DAC Control */
+ { 0x7C30, 0x7C30, 0x0000 }, /* R116 - AIF Test */
+ { 0x0000, 0x0000, 0x0000 }, /* R117 */
+ { 0x0000, 0x0000, 0x0000 }, /* R118 */
+ { 0x0000, 0x0000, 0x0000 }, /* R119 */
+ { 0x0000, 0x0000, 0x0000 }, /* R120 */
+ { 0x0000, 0x0000, 0x0000 }, /* R121 */
+ { 0x0000, 0x0000, 0x0000 }, /* R122 */
+ { 0x0000, 0x0000, 0x0000 }, /* R123 */
+ { 0x0000, 0x0000, 0x0000 }, /* R124 */
+ { 0x0000, 0x0000, 0x0000 }, /* R125 */
+ { 0x0000, 0x0000, 0x0000 }, /* R126 */
+ { 0x0000, 0x0000, 0x0000 }, /* R127 */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R128 - GPIO Debounce */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R129 - GPIO Pin pull up Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R130 - GPIO Pull down Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R131 - GPIO Interrupt Mode */
+ { 0x0000, 0x0000, 0x0000 }, /* R132 */
+ { 0x00C0, 0x00C0, 0x0000 }, /* R133 - GPIO Control */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R134 - GPIO Configuration (i/o) */
+ { 0x1FFF, 0x1FFF, 0x0000 }, /* R135 - GPIO Pin Polarity / Type */
+ { 0x0000, 0x0000, 0x0000 }, /* R136 */
+ { 0x0000, 0x0000, 0x0000 }, /* R137 */
+ { 0x0000, 0x0000, 0x0000 }, /* R138 */
+ { 0x0000, 0x0000, 0x0000 }, /* R139 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R140 - GPIO Function Select 1 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R141 - GPIO Function Select 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R142 - GPIO Function Select 3 */
+ { 0x000F, 0x000F, 0x0000 }, /* R143 - GPIO Function Select 4 */
+ { 0xF0FF, 0xF0FF, 0xA000 }, /* R144 - Digitiser Control (1) */
+ { 0x3707, 0x3707, 0x0000 }, /* R145 - Digitiser Control (2) */
+ { 0x0000, 0x0000, 0x0000 }, /* R146 */
+ { 0x0000, 0x0000, 0x0000 }, /* R147 */
+ { 0x0000, 0x0000, 0x0000 }, /* R148 */
+ { 0x0000, 0x0000, 0x0000 }, /* R149 */
+ { 0x0000, 0x0000, 0x0000 }, /* R150 */
+ { 0x0000, 0x0000, 0x0000 }, /* R151 */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R152 - AUX1 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R153 - AUX2 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R154 - AUX3 Readback */
+ { 0x7FFF, 0x7000, 0xFFFF }, /* R155 - AUX4 Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R156 - USB Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R157 - LINE Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R158 - BATT Voltage Readback */
+ { 0x0FFF, 0x0000, 0xFFFF }, /* R159 - Chip Temp Readback */
+ { 0x0000, 0x0000, 0x0000 }, /* R160 */
+ { 0x0000, 0x0000, 0x0000 }, /* R161 */
+ { 0x0000, 0x0000, 0x0000 }, /* R162 */
+ { 0x000F, 0x000F, 0x0000 }, /* R163 - Generic Comparator Control */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R164 - Generic comparator 1 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R165 - Generic comparator 2 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R166 - Generic comparator 3 */
+ { 0xFFFF, 0xFFFF, 0x0000 }, /* R167 - Generic comparator 4 */
+ { 0xBFFF, 0xBFFF, 0x8000 }, /* R168 - Battery Charger Control 1 */
+ { 0xFFFF, 0x4FFF, 0xB000 }, /* R169 - Battery Charger Control 2 */
+ { 0x007F, 0x007F, 0x0000 }, /* R170 - Battery Charger Control 3 */
+ { 0x0000, 0x0000, 0x0000 }, /* R171 */
+ { 0x903F, 0x903F, 0xFFFF }, /* R172 - Current Sink Driver A */
+ { 0xE333, 0xE333, 0xFFFF }, /* R173 - CSA Flash control */
+ { 0x903F, 0x903F, 0xFFFF }, /* R174 - Current Sink Driver B */
+ { 0xE333, 0xE333, 0xFFFF }, /* R175 - CSB Flash control */
+ { 0x8F3F, 0x8F3F, 0xFFFF }, /* R176 - DCDC/LDO requested */
+ { 0x332D, 0x332D, 0x0000 }, /* R177 - DCDC Active options */
+ { 0x002D, 0x002D, 0x0000 }, /* R178 - DCDC Sleep options */
+ { 0x5177, 0x5177, 0x8000 }, /* R179 - Power-check comparator */
+ { 0x047F, 0x047F, 0x0000 }, /* R180 - DCDC1 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R181 - DCDC1 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R182 - DCDC1 Low Power */
+ { 0x535B, 0x535B, 0x0000 }, /* R183 - DCDC2 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R184 - DCDC2 Timeouts */
+ { 0x0000, 0x0000, 0x0000 }, /* R185 */
+ { 0x047F, 0x047F, 0x0000 }, /* R186 - DCDC3 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R187 - DCDC3 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R188 - DCDC3 Low Power */
+ { 0x047F, 0x047F, 0x0000 }, /* R189 - DCDC4 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R190 - DCDC4 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R191 - DCDC4 Low Power */
+ { 0x535B, 0x535B, 0x0000 }, /* R192 - DCDC5 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R193 - DCDC5 Timeouts */
+ { 0x0000, 0x0000, 0x0000 }, /* R194 */
+ { 0x047F, 0x047F, 0x0000 }, /* R195 - DCDC6 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R196 - DCDC6 Timeouts */
+ { 0x737F, 0x737F, 0x0000 }, /* R197 - DCDC6 Low Power */
+ { 0x0000, 0x0000, 0x0000 }, /* R198 */
+ { 0xFFD3, 0xFFD3, 0x0000 }, /* R199 - Limit Switch Control */
+ { 0x441F, 0x441F, 0x0000 }, /* R200 - LDO1 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R201 - LDO1 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R202 - LDO1 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R203 - LDO2 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R204 - LDO2 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R205 - LDO2 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R206 - LDO3 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R207 - LDO3 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R208 - LDO3 Low Power */
+ { 0x441F, 0x441F, 0x0000 }, /* R209 - LDO4 Control */
+ { 0xFFC0, 0xFFC0, 0x0000 }, /* R210 - LDO4 Timeouts */
+ { 0x331F, 0x331F, 0x0000 }, /* R211 - LDO4 Low Power */
+ { 0x0000, 0x0000, 0x0000 }, /* R212 */
+ { 0x0000, 0x0000, 0x0000 }, /* R213 */
+ { 0x0000, 0x0000, 0x0000 }, /* R214 */
+ { 0x8F3F, 0x8F3F, 0x0000 }, /* R215 - VCC_FAULT Masks */
+ { 0xFF3F, 0xE03F, 0x0000 }, /* R216 - Main Bandgap Control */
+ { 0xEF2F, 0xE02F, 0x0000 }, /* R217 - OSC Control */
+ { 0xF3FF, 0xB3FF, 0xc000 }, /* R218 - RTC Tick Control */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R219 */
+ { 0x09FF, 0x01FF, 0x0000 }, /* R220 - RAM BIST 1 */
+ { 0x0000, 0x0000, 0x0000 }, /* R221 */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R222 */
+ { 0xFFFF, 0xFFFF, 0xFFFF }, /* R223 */
+ { 0x0000, 0x0000, 0x0000 }, /* R224 */
+ { 0x8F3F, 0x0000, 0xFFFF }, /* R225 - DCDC/LDO status */
+ { 0x0000, 0x0000, 0x0000 }, /* R226 */
+ { 0x0000, 0x0000, 0xFFFF }, /* R227 */
+ { 0x0000, 0x0000, 0x0000 }, /* R228 */
+ { 0x0000, 0x0000, 0x0000 }, /* R229 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R230 - GPIO Pin Status */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R231 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R232 */
+ { 0xFFFF, 0x1FFF, 0xFFFF }, /* R233 */
+ { 0x0000, 0x0000, 0x0000 }, /* R234 */
+ { 0x0000, 0x0000, 0x0000 }, /* R235 */
+ { 0x0000, 0x0000, 0x0000 }, /* R236 */
+ { 0x0000, 0x0000, 0x0000 }, /* R237 */
+ { 0x0000, 0x0000, 0x0000 }, /* R238 */
+ { 0x0000, 0x0000, 0x0000 }, /* R239 */
+ { 0x0000, 0x0000, 0x0000 }, /* R240 */
+ { 0x0000, 0x0000, 0x0000 }, /* R241 */
+ { 0x0000, 0x0000, 0x0000 }, /* R242 */
+ { 0x0000, 0x0000, 0x0000 }, /* R243 */
+ { 0x0000, 0x0000, 0x0000 }, /* R244 */
+ { 0x0000, 0x0000, 0x0000 }, /* R245 */
+ { 0x0000, 0x0000, 0x0000 }, /* R246 */
+ { 0x0000, 0x0000, 0x0000 }, /* R247 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R248 */
+ { 0x0000, 0x0000, 0x0000 }, /* R249 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R250 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R251 */
+ { 0x0000, 0x0000, 0x0000 }, /* R252 */
+ { 0xFFFF, 0x0010, 0xFFFF }, /* R253 */
+ { 0x0000, 0x0000, 0x0000 }, /* R254 */
+ { 0x0000, 0x0000, 0x0000 }, /* R255 */
+};
diff --git a/drivers/mfd/wm8400-core.c b/drivers/mfd/wm8400-core.c
new file mode 100644
index 00000000000..6a0cedb5bb8
--- /dev/null
+++ b/drivers/mfd/wm8400-core.c
@@ -0,0 +1,455 @@
+/*
+ * Core driver for WM8400.
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/mfd/wm8400-private.h>
+#include <linux/mfd/wm8400-audio.h>
+
+static struct {
+ u16 readable; /* Mask of readable bits */
+ u16 writable; /* Mask of writable bits */
+ u16 vol; /* Mask of volatile bits */
+ int is_codec; /* Register controlled by codec reset */
+ u16 default_val; /* Value on reset */
+} reg_data[] = {
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x6172 }, /* R0 */
+ { 0x7000, 0x0000, 0x8000, 0, 0x0000 }, /* R1 */
+ { 0xFF17, 0xFF17, 0x0000, 0, 0x0000 }, /* R2 */
+ { 0xEBF3, 0xEBF3, 0x0000, 1, 0x6000 }, /* R3 */
+ { 0x3CF3, 0x3CF3, 0x0000, 1, 0x0000 }, /* R4 */
+ { 0xF1F8, 0xF1F8, 0x0000, 1, 0x4050 }, /* R5 */
+ { 0xFC1F, 0xFC1F, 0x0000, 1, 0x4000 }, /* R6 */
+ { 0xDFDE, 0xDFDE, 0x0000, 1, 0x01C8 }, /* R7 */
+ { 0xFCFC, 0xFCFC, 0x0000, 1, 0x0000 }, /* R8 */
+ { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R9 */
+ { 0xEFFF, 0xEFFF, 0x0000, 1, 0x0040 }, /* R10 */
+ { 0x27F7, 0x27F7, 0x0000, 1, 0x0004 }, /* R11 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R12 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R13 */
+ { 0x1FEF, 0x1FEF, 0x0000, 1, 0x0000 }, /* R14 */
+ { 0x0163, 0x0163, 0x0000, 1, 0x0100 }, /* R15 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R16 */
+ { 0x01FF, 0x01FF, 0x0000, 1, 0x00C0 }, /* R17 */
+ { 0x1FFF, 0x0FFF, 0x0000, 1, 0x0000 }, /* R18 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1000 }, /* R19 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R20 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x1010 }, /* R21 */
+ { 0x0FDD, 0x0FDD, 0x0000, 1, 0x8000 }, /* R22 */
+ { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0800 }, /* R23 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R24 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R25 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R26 */
+ { 0x0000, 0x01DF, 0x0000, 1, 0x008B }, /* R27 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R28 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R29 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0066 }, /* R30 */
+ { 0x0000, 0x0033, 0x0000, 1, 0x0022 }, /* R31 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R32 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0079 }, /* R33 */
+ { 0x0000, 0x0003, 0x0000, 1, 0x0003 }, /* R34 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0003 }, /* R35 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R36 */
+ { 0x0000, 0x003F, 0x0000, 1, 0x0100 }, /* R37 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R38 */
+ { 0x0000, 0x000F, 0x0000, 0, 0x0000 }, /* R39 */
+ { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R40 */
+ { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R41 */
+ { 0x0000, 0x01B7, 0x0000, 1, 0x0000 }, /* R42 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R43 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R44 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R45 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R46 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R47 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R48 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R49 */
+ { 0x0000, 0x01FF, 0x0000, 1, 0x0000 }, /* R50 */
+ { 0x0000, 0x01B3, 0x0000, 1, 0x0180 }, /* R51 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R52 */
+ { 0x0000, 0x0077, 0x0000, 1, 0x0000 }, /* R53 */
+ { 0x0000, 0x00FF, 0x0000, 1, 0x0000 }, /* R54 */
+ { 0x0000, 0x0001, 0x0000, 1, 0x0000 }, /* R55 */
+ { 0x0000, 0x003F, 0x0000, 1, 0x0000 }, /* R56 */
+ { 0x0000, 0x004F, 0x0000, 1, 0x0000 }, /* R57 */
+ { 0x0000, 0x00FD, 0x0000, 1, 0x0000 }, /* R58 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R59 */
+ { 0x1FFF, 0x1FFF, 0x0000, 1, 0x0000 }, /* R60 */
+ { 0xFFFF, 0xFFFF, 0x0000, 1, 0x0000 }, /* R61 */
+ { 0x03FF, 0x03FF, 0x0000, 1, 0x0000 }, /* R62 */
+ { 0x007F, 0x007F, 0x0000, 1, 0x0000 }, /* R63 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R64 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R65 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R66 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R67 */
+ { 0xDFFF, 0xDFFF, 0x0000, 0, 0x0000 }, /* R68 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R69 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R70 */
+ { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R71 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x4400 }, /* R72 */
+ { 0x23FF, 0x23FF, 0x0000, 0, 0x0000 }, /* R73 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R74 */
+ { 0x000E, 0x000E, 0x0000, 0, 0x0008 }, /* R75 */
+ { 0xE00F, 0xE00F, 0x0000, 0, 0x0000 }, /* R76 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R77 */
+ { 0x03C0, 0x03C0, 0x0000, 0, 0x02C0 }, /* R78 */
+ { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R79 */
+ { 0xFFFF, 0xFFFF, 0x0000, 0, 0x0000 }, /* R80 */
+ { 0xFFFF, 0x0000, 0xffff, 0, 0x0000 }, /* R81 */
+ { 0x2BFF, 0x0000, 0xffff, 0, 0x0000 }, /* R82 */
+ { 0x0000, 0x0000, 0x0000, 0, 0x0000 }, /* R83 */
+ { 0x80FF, 0x80FF, 0x0000, 0, 0x00ff }, /* R84 */
+};
+
+static int wm8400_read(struct wm8400 *wm8400, u8 reg, int num_regs, u16 *dest)
+{
+ int i, ret = 0;
+
+ BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+ /* If there are any volatile reads then read back the entire block */
+ for (i = reg; i < reg + num_regs; i++)
+ if (reg_data[i].vol) {
+ ret = wm8400->read_dev(wm8400->io_data, reg,
+ num_regs, dest);
+ if (ret != 0)
+ return ret;
+ for (i = 0; i < num_regs; i++)
+ dest[i] = be16_to_cpu(dest[i]);
+
+ return 0;
+ }
+
+ /* Otherwise use the cache */
+ memcpy(dest, &wm8400->reg_cache[reg], num_regs * sizeof(u16));
+
+ return 0;
+}
+
+static int wm8400_write(struct wm8400 *wm8400, u8 reg, int num_regs,
+ u16 *src)
+{
+ int ret, i;
+
+ BUG_ON(reg + num_regs - 1 > ARRAY_SIZE(wm8400->reg_cache));
+
+ for (i = 0; i < num_regs; i++) {
+ BUG_ON(!reg_data[reg + i].writable);
+ wm8400->reg_cache[reg + i] = src[i];
+ src[i] = cpu_to_be16(src[i]);
+ }
+
+ /* Do the actual I/O */
+ ret = wm8400->write_dev(wm8400->io_data, reg, num_regs, src);
+ if (ret != 0)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * wm8400_reg_read - Single register read
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg: Register to read
+ *
+ * @return Read value
+ */
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg)
+{
+ u16 val;
+
+ mutex_lock(&wm8400->io_lock);
+
+ wm8400_read(wm8400, reg, 1, &val);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return val;
+}
+EXPORT_SYMBOL_GPL(wm8400_reg_read);
+
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data)
+{
+ int ret;
+
+ mutex_lock(&wm8400->io_lock);
+
+ ret = wm8400_read(wm8400, reg, count, data);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_block_read);
+
+/**
+ * wm8400_set_bits - Bitmask write
+ *
+ * @wm8400: Pointer to wm8400 control structure
+ * @reg: Register to access
+ * @mask: Mask of bits to change
+ * @val: Value to set for masked bits
+ */
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val)
+{
+ u16 tmp;
+ int ret;
+
+ mutex_lock(&wm8400->io_lock);
+
+ ret = wm8400_read(wm8400, reg, 1, &tmp);
+ tmp = (tmp & ~mask) | val;
+ if (ret == 0)
+ ret = wm8400_write(wm8400, reg, 1, &tmp);
+
+ mutex_unlock(&wm8400->io_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8400_set_bits);
+
+/**
+ * wm8400_reset_codec_reg_cache - Reset cached codec registers to
+ * their default values.
+ */
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400)
+{
+ int i;
+
+ mutex_lock(&wm8400->io_lock);
+
+ /* Reset all codec registers to their initial value */
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ if (reg_data[i].is_codec)
+ wm8400->reg_cache[i] = reg_data[i].default_val;
+
+ mutex_unlock(&wm8400->io_lock);
+}
+EXPORT_SYMBOL_GPL(wm8400_reset_codec_reg_cache);
+
+/*
+ * wm8400_init - Generic initialisation
+ *
+ * The WM8400 can be configured as either an I2C or SPI device. Probe
+ * functions for each bus set up the accessors then call into this to
+ * set up the device itself.
+ */
+static int wm8400_init(struct wm8400 *wm8400,
+ struct wm8400_platform_data *pdata)
+{
+ u16 reg;
+ int ret, i;
+
+ mutex_init(&wm8400->io_lock);
+
+ wm8400->dev->driver_data = wm8400;
+
+ /* Check that this is actually a WM8400 */
+ ret = wm8400->read_dev(wm8400->io_data, WM8400_RESET_ID, 1, &reg);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "Chip ID register read failed\n");
+ return -EIO;
+ }
+ if (be16_to_cpu(reg) != reg_data[WM8400_RESET_ID].default_val) {
+ dev_err(wm8400->dev, "Device is not a WM8400, ID is %x\n",
+ be16_to_cpu(reg));
+ return -ENODEV;
+ }
+
+ /* We don't know what state the hardware is in and since this
+ * is a PMIC we can't reset it safely so initialise the register
+ * cache from the hardware.
+ */
+ ret = wm8400->read_dev(wm8400->io_data, 0,
+ ARRAY_SIZE(wm8400->reg_cache),
+ wm8400->reg_cache);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "Register cache read failed\n");
+ return -EIO;
+ }
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ wm8400->reg_cache[i] = be16_to_cpu(wm8400->reg_cache[i]);
+
+ /* If the codec is in reset use hard coded values */
+ if (!(wm8400->reg_cache[WM8400_POWER_MANAGEMENT_1] & WM8400_CODEC_ENA))
+ for (i = 0; i < ARRAY_SIZE(wm8400->reg_cache); i++)
+ if (reg_data[i].is_codec)
+ wm8400->reg_cache[i] = reg_data[i].default_val;
+
+ ret = wm8400_read(wm8400, WM8400_ID, 1, &reg);
+ if (ret != 0) {
+ dev_err(wm8400->dev, "ID register read failed: %d\n", ret);
+ return ret;
+ }
+ reg = (reg & WM8400_CHIP_REV_MASK) >> WM8400_CHIP_REV_SHIFT;
+ dev_info(wm8400->dev, "WM8400 revision %x\n", reg);
+
+ if (pdata && pdata->platform_init) {
+ ret = pdata->platform_init(wm8400->dev);
+ if (ret != 0)
+ dev_err(wm8400->dev, "Platform init failed: %d\n",
+ ret);
+ } else
+ dev_warn(wm8400->dev, "No platform initialisation supplied\n");
+
+ return ret;
+}
+
+static void wm8400_release(struct wm8400 *wm8400)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(wm8400->regulators); i++)
+ if (wm8400->regulators[i].name)
+ platform_device_unregister(&wm8400->regulators[i]);
+}
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+static int wm8400_i2c_read(void *io_data, char reg, int count, u16 *dest)
+{
+ struct i2c_client *i2c = io_data;
+ struct i2c_msg xfer[2];
+ int ret;
+
+ /* Write register */
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = 0;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ /* Read data */
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = count * sizeof(u16);
+ xfer[1].buf = (u8 *)dest;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret == 2)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ return ret;
+}
+
+static int wm8400_i2c_write(void *io_data, char reg, int count, const u16 *src)
+{
+ struct i2c_client *i2c = io_data;
+ u8 *msg;
+ int ret;
+
+ /* We add 1 byte for device register - ideally I2C would gather. */
+ msg = kmalloc((count * sizeof(u16)) + 1, GFP_KERNEL);
+ if (msg == NULL)
+ return -ENOMEM;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, count * sizeof(u16));
+
+ ret = i2c_master_send(i2c, msg, (count * sizeof(u16)) + 1);
+
+ if (ret == (count * 2) + 1)
+ ret = 0;
+ else if (ret >= 0)
+ ret = -EIO;
+
+ kfree(msg);
+
+ return ret;
+}
+
+static int wm8400_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct wm8400 *wm8400;
+ int ret;
+
+ wm8400 = kzalloc(sizeof(struct wm8400), GFP_KERNEL);
+ if (wm8400 == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ wm8400->io_data = i2c;
+ wm8400->read_dev = wm8400_i2c_read;
+ wm8400->write_dev = wm8400_i2c_write;
+ wm8400->dev = &i2c->dev;
+ i2c_set_clientdata(i2c, wm8400);
+
+ ret = wm8400_init(wm8400, i2c->dev.platform_data);
+ if (ret != 0)
+ goto struct_err;
+
+ return 0;
+
+struct_err:
+ i2c_set_clientdata(i2c, NULL);
+ kfree(wm8400);
+err:
+ return ret;
+}
+
+static int wm8400_i2c_remove(struct i2c_client *i2c)
+{
+ struct wm8400 *wm8400 = i2c_get_clientdata(i2c);
+
+ wm8400_release(wm8400);
+ i2c_set_clientdata(i2c, NULL);
+ kfree(wm8400);
+
+ return 0;
+}
+
+static const struct i2c_device_id wm8400_i2c_id[] = {
+ { "wm8400", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, wm8400_i2c_id);
+
+static struct i2c_driver wm8400_i2c_driver = {
+ .driver = {
+ .name = "WM8400",
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8400_i2c_probe,
+ .remove = wm8400_i2c_remove,
+ .id_table = wm8400_i2c_id,
+};
+#endif
+
+static int __init wm8400_module_init(void)
+{
+ int ret = -ENODEV;
+
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ ret = i2c_add_driver(&wm8400_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register I2C driver: %d\n", ret);
+#endif
+
+ return ret;
+}
+module_init(wm8400_module_init);
+
+static void __exit wm8400_module_exit(void)
+{
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ i2c_del_driver(&wm8400_i2c_driver);
+#endif
+}
+module_exit(wm8400_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index a726f3b01a6..efd3aa08b88 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -15,7 +15,7 @@ if MISC_DEVICES
config ATMEL_PWM
tristate "Atmel AT32/AT91 PWM support"
- depends on AVR32 || ARCH_AT91
+ depends on AVR32 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91CAP9
help
This option enables device driver support for the PWM channels
on certain Atmel prcoessors. Pulse Width Modulation is used for
@@ -409,6 +409,7 @@ config EEEPC_LAPTOP
depends on BACKLIGHT_CLASS_DEVICE
depends on HWMON
depends on EXPERIMENTAL
+ depends on RFKILL
---help---
This driver supports the Fn-Fx keys on Eee PC laptops.
It also adds the ability to switch camera/wlan on/off.
diff --git a/drivers/misc/hp-wmi.c b/drivers/misc/hp-wmi.c
index 6d407c2a4f9..5dabfb69ee5 100644
--- a/drivers/misc/hp-wmi.c
+++ b/drivers/misc/hp-wmi.c
@@ -309,7 +309,7 @@ static int hp_wmi_setkeycode(struct input_dev *dev, int scancode, int keycode)
return -EINVAL;
}
-void hp_wmi_notify(u32 value, void *context)
+static void hp_wmi_notify(u32 value, void *context)
{
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
static struct key_entry *key;
diff --git a/drivers/misc/sgi-gru/gru.h b/drivers/misc/sgi-gru/gru.h
index 40df7cb3f0a..f93f03a9e6e 100644
--- a/drivers/misc/sgi-gru/gru.h
+++ b/drivers/misc/sgi-gru/gru.h
@@ -30,9 +30,9 @@
/*
* Size used to map GRU GSeg
*/
-#if defined CONFIG_IA64
+#if defined(CONFIG_IA64)
#define GRU_GSEG_PAGESIZE (256 * 1024UL)
-#elif defined CONFIG_X86_64
+#elif defined(CONFIG_X86_64)
#define GRU_GSEG_PAGESIZE (256 * 1024UL) /* ZZZ 2MB ??? */
#else
#error "Unsupported architecture"
diff --git a/drivers/misc/sgi-gru/gru_instructions.h b/drivers/misc/sgi-gru/gru_instructions.h
index 0dc36225c7c..48762e7b98b 100644
--- a/drivers/misc/sgi-gru/gru_instructions.h
+++ b/drivers/misc/sgi-gru/gru_instructions.h
@@ -26,7 +26,7 @@
* Architecture dependent functions
*/
-#if defined CONFIG_IA64
+#if defined(CONFIG_IA64)
#include <linux/compiler.h>
#include <asm/intrinsics.h>
#define __flush_cache(p) ia64_fc(p)
@@ -36,7 +36,7 @@
barrier(); \
*((volatile int *)(p)) = v; /* force st.rel */ \
} while (0)
-#elif defined CONFIG_X86_64
+#elif defined(CONFIG_X86_64)
#define __flush_cache(p) clflush(p)
#define gru_ordered_store_int(p,v) \
do { \
@@ -299,6 +299,7 @@ static inline void gru_flush_cache(void *p)
static inline void gru_start_instruction(struct gru_instruction *ins, int op32)
{
gru_ordered_store_int(ins, op32);
+ gru_flush_cache(ins);
}
@@ -604,8 +605,9 @@ static inline int gru_get_cb_substatus(void *cb)
static inline int gru_check_status(void *cb)
{
struct gru_control_block_status *cbs = (void *)cb;
- int ret = cbs->istatus;
+ int ret;
+ ret = cbs->istatus;
if (ret == CBS_CALL_OS)
ret = gru_check_status_proc(cb);
return ret;
@@ -617,7 +619,7 @@ static inline int gru_check_status(void *cb)
static inline int gru_wait(void *cb)
{
struct gru_control_block_status *cbs = (void *)cb;
- int ret = cbs->istatus;;
+ int ret = cbs->istatus;
if (ret != CBS_IDLE)
ret = gru_wait_proc(cb);
diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index 3d33015bbf3..8c389d606c3 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -214,12 +214,14 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
}
/*
- *
* atomic_pte_lookup
*
* Convert a user virtual address to a physical address
* Only supports Intel large pages (2MB only) on x86_64.
* ZZZ - hugepage support is incomplete
+ *
+ * NOTE: mmap_sem is already held on entry to this function. This
+ * guarantees existence of the page tables.
*/
static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
int write, unsigned long *paddr, int *pageshift)
@@ -229,9 +231,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
pud_t *pudp;
pte_t pte;
- WARN_ON(irqs_disabled()); /* ZZZ debug */
-
- local_irq_disable();
pgdp = pgd_offset(vma->vm_mm, vaddr);
if (unlikely(pgd_none(*pgdp)))
goto err;
@@ -250,8 +249,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
#endif
pte = *pte_offset_kernel(pmdp, vaddr);
- local_irq_enable();
-
if (unlikely(!pte_present(pte) ||
(write && (!pte_write(pte) || !pte_dirty(pte)))))
return 1;
@@ -324,6 +321,7 @@ static int gru_try_dropin(struct gru_thread_state *gts,
* Atomic lookup is faster & usually works even if called in non-atomic
* context.
*/
+ rmb(); /* Must/check ms_range_active before loading PTEs */
ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &pageshift);
if (ret) {
if (!cb)
@@ -543,6 +541,7 @@ int gru_get_exception_detail(unsigned long arg)
ucbnum = get_cb_number((void *)excdet.cb);
cbrnum = thread_cbr_number(gts, ucbnum);
cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
+ prefetchw(cbe); /* Harmless on hardware, required for emulator */
excdet.opc = cbe->opccpy;
excdet.exopc = cbe->exopccpy;
excdet.ecause = cbe->ecause;
diff --git a/drivers/misc/sgi-gru/grufile.c b/drivers/misc/sgi-gru/grufile.c
index d61cee796ef..5c027b6b4e5 100644
--- a/drivers/misc/sgi-gru/grufile.c
+++ b/drivers/misc/sgi-gru/grufile.c
@@ -113,7 +113,7 @@ static int gru_file_mmap(struct file *file, struct vm_area_struct *vma)
return -EPERM;
if (vma->vm_start & (GRU_GSEG_PAGESIZE - 1) ||
- vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
+ vma->vm_end & (GRU_GSEG_PAGESIZE - 1))
return -EINVAL;
vma->vm_flags |=
@@ -398,6 +398,12 @@ static int __init gru_init(void)
irq = get_base_irq();
for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) {
ret = request_irq(irq + chip, gru_intr, 0, id, NULL);
+ /* TODO: fix irq handling on x86. For now ignore failures because
+ * interrupts are not required & not yet fully supported */
+ if (ret) {
+ printk("!!!WARNING: GRU ignoring request failure!!!\n");
+ ret = 0;
+ }
if (ret) {
printk(KERN_ERR "%s: request_irq failed\n",
GRU_DRIVER_ID_STR);
diff --git a/drivers/misc/sgi-gru/gruhandles.h b/drivers/misc/sgi-gru/gruhandles.h
index d16031d6267..b63018d60fe 100644
--- a/drivers/misc/sgi-gru/gruhandles.h
+++ b/drivers/misc/sgi-gru/gruhandles.h
@@ -91,12 +91,7 @@
#define GSEGPOFF(h) ((h) & (GRU_SIZE - 1))
/* Convert an arbitrary handle address to the beginning of the GRU segment */
-#ifndef __PLUGIN__
#define GRUBASE(h) ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1)))
-#else
-extern void *gmu_grubase(void *h);
-#define GRUBASE(h) gmu_grubase(h)
-#endif
/* General addressing macros. */
static inline void *get_gseg_base_address(void *base, int ctxnum)
diff --git a/drivers/misc/sgi-gru/grukservices.c b/drivers/misc/sgi-gru/grukservices.c
index dfd49af0fe1..880c55dfb66 100644
--- a/drivers/misc/sgi-gru/grukservices.c
+++ b/drivers/misc/sgi-gru/grukservices.c
@@ -122,6 +122,7 @@ int gru_get_cb_exception_detail(void *cb,
struct gru_control_block_extended *cbe;
cbe = get_cbe(GRUBASE(cb), get_cb_number(cb));
+ prefetchw(cbe); /* Harmless on hardware, required for emulator */
excdet->opc = cbe->opccpy;
excdet->exopc = cbe->exopccpy;
excdet->ecause = cbe->ecause;
@@ -466,7 +467,7 @@ int gru_send_message_gpa(unsigned long mq, void *mesg, unsigned int bytes)
STAT(mesq_send);
BUG_ON(bytes < sizeof(int) || bytes > 2 * GRU_CACHE_LINE_BYTES);
- clines = (bytes + GRU_CACHE_LINE_BYTES - 1) / GRU_CACHE_LINE_BYTES;
+ clines = DIV_ROUND_UP(bytes, GRU_CACHE_LINE_BYTES);
if (gru_get_cpu_resources(bytes, &cb, &dsr))
return MQE_BUG_NO_RESOURCES;
memcpy(dsr, mesg, bytes);
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c
index 0eeb8dddd2f..e11e1ac5090 100644
--- a/drivers/misc/sgi-gru/grumain.c
+++ b/drivers/misc/sgi-gru/grumain.c
@@ -432,29 +432,35 @@ static inline long gru_copy_handle(void *d, void *s)
return GRU_HANDLE_BYTES;
}
-/* rewrite in assembly & use lots of prefetch */
-static void gru_load_context_data(void *save, void *grubase, int ctxnum,
- unsigned long cbrmap, unsigned long dsrmap)
+static void gru_prefetch_context(void *gseg, void *cb, void *cbe, unsigned long cbrmap,
+ unsigned long length)
{
- void *gseg, *cb, *cbe;
- unsigned long length;
int i, scr;
- gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
- length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
prefetch_data(gseg + GRU_DS_BASE, length / GRU_CACHE_LINE_BYTES,
GRU_CACHE_LINE_BYTES);
- cb = gseg + GRU_CB_BASE;
- cbe = grubase + GRU_CBE_BASE;
for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
prefetch_data(cb, 1, GRU_CACHE_LINE_BYTES);
prefetch_data(cbe + i * GRU_HANDLE_STRIDE, 1,
GRU_CACHE_LINE_BYTES);
cb += GRU_HANDLE_STRIDE;
}
+}
+
+static void gru_load_context_data(void *save, void *grubase, int ctxnum,
+ unsigned long cbrmap, unsigned long dsrmap)
+{
+ void *gseg, *cb, *cbe;
+ unsigned long length;
+ int i, scr;
+ gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
cb = gseg + GRU_CB_BASE;
+ cbe = grubase + GRU_CBE_BASE;
+ length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
+ gru_prefetch_context(gseg, cb, cbe, cbrmap, length);
+
for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
save += gru_copy_handle(cb, save);
save += gru_copy_handle(cbe + i * GRU_HANDLE_STRIDE, save);
@@ -472,15 +478,16 @@ static void gru_unload_context_data(void *save, void *grubase, int ctxnum,
int i, scr;
gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
-
cb = gseg + GRU_CB_BASE;
cbe = grubase + GRU_CBE_BASE;
+ length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
+ gru_prefetch_context(gseg, cb, cbe, cbrmap, length);
+
for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
save += gru_copy_handle(save, cb);
save += gru_copy_handle(save, cbe + i * GRU_HANDLE_STRIDE);
cb += GRU_HANDLE_STRIDE;
}
- length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
memcpy(save, gseg + GRU_DS_BASE, length);
}
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index 26d42987971..782994ead0e 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -145,7 +145,7 @@ static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
static int ams_delta_nand_ready(struct mtd_info *mtd)
{
- return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
+ return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
}
/*
@@ -185,7 +185,7 @@ static int __init ams_delta_init(void)
this->read_buf = ams_delta_read_buf;
this->verify_buf = ams_delta_verify_buf;
this->cmd_ctrl = ams_delta_hwcontrol;
- if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
+ if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
this->dev_ready = ams_delta_nand_ready;
} else {
this->dev_ready = NULL;
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 5ba4bab6d43..7d15e7c6bca 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -17,7 +17,7 @@
Annapolis MD 21403
Fixed (again!) the missing interrupt locking on TX/RX shifting.
- Alan Cox <Alan.Cox@linux.org>
+ Alan Cox <alan@lxorguk.ukuu.org.uk>
Removed calls to init_etherdev since they are no longer needed, and
cleaned up modularization just a bit. The driver still allows only
@@ -29,16 +29,16 @@
the board. Now getting 150K/second FTP with a 3c501 card. Still playing
with a TX-TX optimisation to see if we can touch 180-200K/second as seems
theoretically maximum.
- 19950402 Alan Cox <Alan.Cox@linux.org>
+ 19950402 Alan Cox <alan@lxorguk.ukuu.org.uk>
Cleaned up for 2.3.x because we broke SMP now.
- 20000208 Alan Cox <alan@redhat.com>
+ 20000208 Alan Cox <alan@lxorguk.ukuu.org.uk>
Check up pass for 2.5. Nothing significant changed
- 20021009 Alan Cox <alan@redhat.com>
+ 20021009 Alan Cox <alan@lxorguk.ukuu.org.uk>
Fixed zero fill corner case
- 20030104 Alan Cox <alan@redhat.com>
+ 20030104 Alan Cox <alan@lxorguk.ukuu.org.uk>
For the avoidance of doubt the "preferred form" of this code is one which
@@ -104,7 +104,7 @@
static const char version[] =
- DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@redhat.com).\n";
+ DRV_NAME ".c: " DRV_VERSION " Alan Cox (alan@lxorguk.ukuu.org.uk).\n";
/*
* Braindamage remaining:
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index b9d097c9f6b..3a7bc524af3 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -40,7 +40,7 @@
v1.14 10/15/97 Avoided waiting..discard message for fast machines -djb
v1.15 1/31/98 Faster recovery for Tx errors. -djb
v1.16 2/3/98 Different ID port handling to avoid sound cards. -djb
- v1.18 12Mar2001 Andrew Morton <andrewm@uow.edu.au>
+ v1.18 12Mar2001 Andrew Morton
- Avoid bogus detect of 3c590's (Andrzej Krzysztofowicz)
- Reviewed against 1.18 from scyld.com
v1.18a 17Nov2001 Jeff Garzik <jgarzik@pobox.com>
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index e4e3241628d..a0f8b6e2d0a 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -18,7 +18,7 @@
2001/11/17 - Added ethtool support (jgarzik)
- 2002/10/28 - Locking updates for 2.5 (alan@redhat.com)
+ 2002/10/28 - Locking updates for 2.5 (alan@lxorguk.ukuu.org.uk)
*/
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e9d529442b0..1d8af334833 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2400,7 +2400,7 @@ config EHEA
will be called ehea.
config ENIC
- tristate "E, the Cisco 10G Ethernet NIC"
+ tristate "Cisco 10G Ethernet NIC support"
depends on PCI && INET
select INET_LRO
help
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index a0b4c851607..735fc947640 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -4,7 +4,7 @@
* - Jay Schulist <jschlst@samba.org>
*
* With more than a little help from;
- * - Alan Cox <Alan.Cox@linux.org>
+ * - Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Derived from:
* - skeleton.c: A network driver outline for linux.
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index a28de818280..7107620f615 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -36,8 +36,7 @@
Alan Cox : Removed 1.2 support, added 2.1 extra counters.
- Andrew Morton : andrewm@uow.edu.au
- : Kernel 2.3.48
+ Andrew Morton : Kernel 2.3.48
: Handle kmalloc() failures
: Other resource allocation fixes
: Add SMP locks
@@ -49,7 +48,7 @@
: Fixed an out-of-mem bug in dma_rx()
: Updated Documentation/networking/cs89x0.txt
- Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre1
+ Andrew Morton : Kernel 2.3.99-pre1
: Use skb_reserve to longword align IP header (two places)
: Remove a delay loop from dma_rx()
: Replace '100' with HZ
@@ -57,11 +56,11 @@
: Added 'cs89x0_dma=N' kernel boot option
: Correctly initialise lp->lock in non-module compile
- Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1
+ Andrew Morton : Kernel 2.3.99-pre4-1
: MOD_INC/DEC race fix (see
: http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html)
- Andrew Morton : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2
+ Andrew Morton : Kernel 2.4.0-test7-pre2
: Enhanced EEPROM support to cover more devices,
: abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch
: (Jason Gunthorpe <jgg@ualberta.ca>)
@@ -156,7 +155,7 @@
#include "cs89x0.h"
static char version[] __initdata =
-"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>\n";
+"cs89x0.c: v2.4.3-pre1 Russell Nelson <nelson@crynwr.com>, Andrew Morton\n";
#define DRV_NAME "cs89x0"
@@ -1877,7 +1876,7 @@ MODULE_PARM_DESC(dmasize , "(ignored)");
MODULE_PARM_DESC(use_dma , "(ignored)");
#endif
-MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton <andrewm@uow.edu.au>");
+MODULE_AUTHOR("Mike Cruse, Russwll Nelson <nelson@crynwr.com>, Andrew Morton");
MODULE_LICENSE("GPL");
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
index 455ef529cd6..bc8e2413abd 100644
--- a/drivers/net/cxgb3/adapter.h
+++ b/drivers/net/cxgb3/adapter.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
index 744fac0b161..5c3c05da4d9 100644
--- a/drivers/net/cxgb3/ael1002.c
+++ b/drivers/net/cxgb3/ael1002.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
index 593fb643a61..e312d315a42 100644
--- a/drivers/net/cxgb3/common.h
+++ b/drivers/net/cxgb3/common.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
index 6ad92405d9a..1d8d46eb3c9 100644
--- a/drivers/net/cxgb3/cxgb3_ctl_defs.h
+++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
index 45e92164c26..47e53769af5 100644
--- a/drivers/net/cxgb3/cxgb3_defs.h
+++ b/drivers/net/cxgb3/cxgb3_defs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
index 3e8d5faec3a..b19e4376ba7 100644
--- a/drivers/net/cxgb3/cxgb3_ioctl.h
+++ b/drivers/net/cxgb3/cxgb3_ioctl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
index f31985df0bb..1ace41a13ac 100644
--- a/drivers/net/cxgb3/cxgb3_main.c
+++ b/drivers/net/cxgb3/cxgb3_main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
index 0f6fd63b284..265aa8a15af 100644
--- a/drivers/net/cxgb3/cxgb3_offload.c
+++ b/drivers/net/cxgb3/cxgb3_offload.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
index 7a379138b5a..d514e5019df 100644
--- a/drivers/net/cxgb3/cxgb3_offload.h
+++ b/drivers/net/cxgb3/cxgb3_offload.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
index b75ddd8777f..0d9b0e6dccf 100644
--- a/drivers/net/cxgb3/firmware_exports.h
+++ b/drivers/net/cxgb3/firmware_exports.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
index b2c5314582a..4407ac9bb55 100644
--- a/drivers/net/cxgb3/l2t.c
+++ b/drivers/net/cxgb3/l2t.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
index 42ce65f76a8..fd3eb07e3f4 100644
--- a/drivers/net/cxgb3/l2t.h
+++ b/drivers/net/cxgb3/l2t.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
index 4c4d6e877ea..3b5517b8fbd 100644
--- a/drivers/net/cxgb3/mc5.c
+++ b/drivers/net/cxgb3/mc5.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
index 87919419b70..c6480be0bc1 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
index 917970ed24a..852c399a8b0 100644
--- a/drivers/net/cxgb3/t3_cpl.h
+++ b/drivers/net/cxgb3/t3_cpl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2004-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
index 4da5b09b9bc..968f64be374 100644
--- a/drivers/net/cxgb3/t3_hw.c
+++ b/drivers/net/cxgb3/t3_hw.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
index 0a21cfbd2b2..be55e9ae74d 100644
--- a/drivers/net/cxgb3/t3cdev.h
+++ b/drivers/net/cxgb3/t3cdev.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2007 Chelsio Communications. All rights reserved.
+ * Copyright (C) 2006-2008 Chelsio Communications. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 29db711303b..bb8698a8675 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2003-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -35,7 +35,7 @@
#define DRV_DESC "Chelsio T3 Network Driver"
#define DRV_NAME "cxgb3"
/* Driver version */
-#define DRV_VERSION "1.0-ko"
+#define DRV_VERSION "1.1.0-ko"
/* Firmware version */
#define FW_VERSION_MAJOR 7
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
index 306c2dc4ab3..33f956bd6b5 100644
--- a/drivers/net/cxgb3/vsc8211.c
+++ b/drivers/net/cxgb3/vsc8211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
index ffdc0a1892b..9d7786937aa 100644
--- a/drivers/net/cxgb3/xgmac.c
+++ b/drivers/net/cxgb3/xgmac.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2005-2008 Chelsio, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 795c594a4b7..b751c1b96cf 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -8,7 +8,7 @@
*
* Many modifications, and currently maintained, by
* Philip Blundell <philb@gnu.org>
- * Added the Compaq LTE Alan Cox <alan@redhat.com>
+ * Added the Compaq LTE Alan Cox <alan@lxorguk.ukuu.org.uk>
* Added MCA support Adam Fritzler
*
* Note - this driver is experimental still - it has problems on faster
diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c
index f3a47a87dbb..180e968dc54 100644
--- a/drivers/net/enic/enic_main.c
+++ b/drivers/net/enic/enic_main.c
@@ -34,6 +34,7 @@
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
+#include <net/ip6_checksum.h>
#include "cq_enet_desc.h"
#include "vnic_dev.h"
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig
index bcec7320895..78a1628c989 100644
--- a/drivers/net/ibm_newemac/Kconfig
+++ b/drivers/net/ibm_newemac/Kconfig
@@ -62,3 +62,15 @@ config IBM_NEW_EMAC_TAH
config IBM_NEW_EMAC_EMAC4
bool
default n
+
+config IBM_NEW_EMAC_NO_FLOW_CTRL
+ bool
+ default n
+
+config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+ bool
+ default n
+
+config IBM_NEW_EMAC_MAL_COMMON_ERR
+ bool
+ default n
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 58dfd32ccca..efcf21c9f5c 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -202,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode)
{
return phy_mode == PHY_MODE_GMII ||
phy_mode == PHY_MODE_RGMII ||
+ phy_mode == PHY_MODE_SGMII ||
phy_mode == PHY_MODE_TBI ||
phy_mode == PHY_MODE_RTBI;
}
static inline int emac_phy_gpcs(int phy_mode)
{
- return phy_mode == PHY_MODE_TBI ||
+ return phy_mode == PHY_MODE_SGMII ||
+ phy_mode == PHY_MODE_TBI ||
phy_mode == PHY_MODE_RTBI;
}
@@ -562,8 +564,9 @@ static int emac_configure(struct emac_instance *dev)
switch (dev->phy.speed) {
case SPEED_1000:
if (emac_phy_gpcs(dev->phy.mode)) {
- mr1 |= EMAC_MR1_MF_1000GPCS |
- EMAC_MR1_MF_IPPA(dev->phy.address);
+ mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA(
+ (dev->phy.gpcs_address != 0xffffffff) ?
+ dev->phy.gpcs_address : dev->phy.address);
/* Put some arbitrary OUI, Manuf & Rev IDs so we can
* identify this GPCS PHY later.
@@ -675,8 +678,12 @@ static int emac_configure(struct emac_instance *dev)
out_be32(&p->iser, r);
/* We need to take GPCS PHY out of isolate mode after EMAC reset */
- if (emac_phy_gpcs(dev->phy.mode))
- emac_mii_reset_phy(&dev->phy);
+ if (emac_phy_gpcs(dev->phy.mode)) {
+ if (dev->phy.gpcs_address != 0xffffffff)
+ emac_mii_reset_gpcs(&dev->phy);
+ else
+ emac_mii_reset_phy(&dev->phy);
+ }
return 0;
}
@@ -881,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg)
struct emac_instance *dev = netdev_priv(ndev);
int res;
- res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev,
+ res = __emac_mdio_read((dev->mdio_instance &&
+ dev->phy.gpcs_address != id) ?
+ dev->mdio_instance : dev,
(u8) id, (u8) reg);
return res;
}
@@ -890,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val)
{
struct emac_instance *dev = netdev_priv(ndev);
- __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev,
+ __emac_mdio_write((dev->mdio_instance &&
+ dev->phy.gpcs_address != id) ?
+ dev->mdio_instance : dev,
(u8) id, (u8) reg, (u16) val);
}
@@ -2382,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
* XXX I probably should move these settings to the dev tree
*/
dev->phy.address = -1;
- dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII;
+ dev->phy.features = SUPPORTED_MII;
+ if (emac_phy_supports_gige(dev->phy_mode))
+ dev->phy.features |= SUPPORTED_1000baseT_Full;
+ else
+ dev->phy.features |= SUPPORTED_100baseT_Full;
dev->phy.pause = 1;
return 0;
@@ -2421,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev)
* Note that the busy_phy_map is currently global
* while it should probably be per-ASIC...
*/
- dev->phy.address = dev->cell_index;
+ dev->phy.gpcs_address = dev->gpcs_address;
+ if (dev->phy.gpcs_address == 0xffffffff)
+ dev->phy.address = dev->cell_index;
}
emac_configure(dev);
@@ -2531,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
dev->phy_address = 0xffffffff;
if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0))
dev->phy_map = 0xffffffff;
+ if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0))
+ dev->gpcs_address = 0xffffffff;
if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1))
return -ENXIO;
if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0))
@@ -2585,6 +2604,8 @@ static int __devinit emac_init_config(struct emac_instance *dev)
if (of_device_is_compatible(np, "ibm,emac-440ep") ||
of_device_is_compatible(np, "ibm,emac-440gr"))
dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
+ if (of_device_is_compatible(np, "ibm,emac-405ez"))
+ dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x;
}
/* Fixup some feature bits based on the device tree */
@@ -2842,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev,
ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2],
ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]);
+ if (dev->phy_mode == PHY_MODE_SGMII)
+ printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name);
+
if (dev->phy.address >= 0)
printk("%s: found %s PHY (0x%02x)\n", ndev->name,
dev->phy.def->name, dev->phy.address);
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h
index 5ca70e55b6c..18d56c6c423 100644
--- a/drivers/net/ibm_newemac/core.h
+++ b/drivers/net/ibm_newemac/core.h
@@ -190,6 +190,9 @@ struct emac_instance {
struct delayed_work link_work;
int link_polling;
+ /* GPCS PHY infos */
+ u32 gpcs_address;
+
/* Shared MDIO if any */
u32 mdio_ph;
struct of_device *mdio_dev;
@@ -345,6 +348,9 @@ enum {
#ifdef CONFIG_IBM_NEW_EMAC_RGMII
EMAC_FTR_HAS_RGMII |
#endif
+#ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL
+ EMAC_FTR_NO_FLOW_CONTROL_40x |
+#endif
EMAC_FTR_460EX_PHY_CLK_FIX |
EMAC_FTR_440EP_PHY_CLK_FIX,
};
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c
index 10c267b2b96..1839d3f154a 100644
--- a/drivers/net/ibm_newemac/mal.c
+++ b/drivers/net/ibm_newemac/mal.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include "core.h"
+#include <asm/dcr-regs.h>
static int mal_count;
@@ -279,6 +280,10 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance)
mal_schedule_poll(mal);
set_mal_dcrn(mal, MAL_TXEOBISR, r);
+ if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
+ mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
+ (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX));
+
return IRQ_HANDLED;
}
@@ -293,6 +298,10 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance)
mal_schedule_poll(mal);
set_mal_dcrn(mal, MAL_RXEOBISR, r);
+ if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT))
+ mtdcri(SDR0, DCRN_SDR_ICINTSTAT,
+ (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX));
+
return IRQ_HANDLED;
}
@@ -336,6 +345,25 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance)
return IRQ_HANDLED;
}
+static irqreturn_t mal_int(int irq, void *dev_instance)
+{
+ struct mal_instance *mal = dev_instance;
+ u32 esr = get_mal_dcrn(mal, MAL_ESR);
+
+ if (esr & MAL_ESR_EVB) {
+ /* descriptor error */
+ if (esr & MAL_ESR_DE) {
+ if (esr & MAL_ESR_CIDT)
+ return mal_rxde(irq, dev_instance);
+ else
+ return mal_txde(irq, dev_instance);
+ } else { /* SERR */
+ return mal_serr(irq, dev_instance);
+ }
+ }
+ return IRQ_HANDLED;
+}
+
void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac)
{
/* Spinlock-type semantics: only one caller disable poll at a time */
@@ -493,6 +521,8 @@ static int __devinit mal_probe(struct of_device *ofdev,
unsigned int dcr_base;
const u32 *prop;
u32 cfg;
+ unsigned long irqflags;
+ irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde;
mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL);
if (!mal) {
@@ -542,11 +572,21 @@ static int __devinit mal_probe(struct of_device *ofdev,
goto fail;
}
+ if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez"))
+ mal->features |= (MAL_FTR_CLEAR_ICINTSTAT |
+ MAL_FTR_COMMON_ERR_INT);
+
mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0);
mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1);
mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2);
- mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
- mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+
+ if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
+ mal->txde_irq = mal->rxde_irq = mal->serr_irq;
+ } else {
+ mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3);
+ mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4);
+ }
+
if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ ||
mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ ||
mal->rxde_irq == NO_IRQ) {
@@ -608,16 +648,26 @@ static int __devinit mal_probe(struct of_device *ofdev,
sizeof(struct mal_descriptor) *
mal_rx_bd_offset(mal, i));
- err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal);
+ if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) {
+ irqflags = IRQF_SHARED;
+ hdlr_serr = hdlr_txde = hdlr_rxde = mal_int;
+ } else {
+ irqflags = 0;
+ hdlr_serr = mal_serr;
+ hdlr_txde = mal_txde;
+ hdlr_rxde = mal_rxde;
+ }
+
+ err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal);
if (err)
goto fail2;
- err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal);
+ err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal);
if (err)
goto fail3;
err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal);
if (err)
goto fail4;
- err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal);
+ err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal);
if (err)
goto fail5;
err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal);
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h
index 717dc38b685..2f0a8736084 100644
--- a/drivers/net/ibm_newemac/mal.h
+++ b/drivers/net/ibm_newemac/mal.h
@@ -213,6 +213,8 @@ struct mal_instance {
struct of_device *ofdev;
int index;
spinlock_t lock;
+
+ unsigned int features;
};
static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg)
@@ -225,6 +227,38 @@ static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val)
dcr_write(mal->dcr_host, reg, val);
}
+/* Features of various MAL implementations */
+
+/* Set if you have interrupt coalescing and you have to clear the SDR
+ * register for TXEOB and RXEOB interrupts to work
+ */
+#define MAL_FTR_CLEAR_ICINTSTAT 0x00000001
+
+/* Set if your MAL has SERR, TXDE, and RXDE OR'd into a single UIC
+ * interrupt
+ */
+#define MAL_FTR_COMMON_ERR_INT 0x00000002
+
+enum {
+ MAL_FTRS_ALWAYS = 0,
+
+ MAL_FTRS_POSSIBLE =
+#ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT
+ MAL_FTR_CLEAR_ICINTSTAT |
+#endif
+#ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR
+ MAL_FTR_COMMON_ERR_INT |
+#endif
+ 0,
+};
+
+static inline int mal_has_feature(struct mal_instance *dev,
+ unsigned long feature)
+{
+ return (MAL_FTRS_ALWAYS & feature) ||
+ (MAL_FTRS_POSSIBLE & dev->features & feature);
+}
+
/* Register MAL devices */
int mal_init(void);
void mal_exit(void);
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c
index 9164abb72d9..c40cd8df221 100644
--- a/drivers/net/ibm_newemac/phy.c
+++ b/drivers/net/ibm_newemac/phy.c
@@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val)
phy->mdio_write(phy->dev, phy->address, reg, val);
}
+static inline int gpcs_phy_read(struct mii_phy *phy, int reg)
+{
+ return phy->mdio_read(phy->dev, phy->gpcs_address, reg);
+}
+
+static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val)
+{
+ phy->mdio_write(phy->dev, phy->gpcs_address, reg, val);
+}
+
int emac_mii_reset_phy(struct mii_phy *phy)
{
int val;
@@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy)
return limit <= 0;
}
+int emac_mii_reset_gpcs(struct mii_phy *phy)
+{
+ int val;
+ int limit = 10000;
+
+ val = gpcs_phy_read(phy, MII_BMCR);
+ val &= ~(BMCR_ISOLATE | BMCR_ANENABLE);
+ val |= BMCR_RESET;
+ gpcs_phy_write(phy, MII_BMCR, val);
+
+ udelay(300);
+
+ while (limit--) {
+ val = gpcs_phy_read(phy, MII_BMCR);
+ if (val >= 0 && (val & BMCR_RESET) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & BMCR_ISOLATE) && limit > 0)
+ gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE);
+
+ if (limit > 0 && phy->mode == PHY_MODE_SGMII) {
+ /* Configure GPCS interface to recommended setting for SGMII */
+ gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */
+ gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */
+ gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */
+ }
+
+ return limit <= 0;
+}
+
static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
{
int ctl, adv;
@@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy)
return 0;
}
+static int m88e1112_init(struct mii_phy *phy)
+{
+ /*
+ * Marvell 88E1112 PHY needs to have the SGMII MAC
+ * interace (page 2) properly configured to
+ * communicate with the 460EX/GT GPCS interface.
+ */
+
+ u16 reg_short;
+
+ pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__);
+
+ /* Set access to Page 2 */
+ phy_write(phy, 0x16, 0x0002);
+
+ phy_write(phy, 0x00, 0x0040); /* 1Gbps */
+ reg_short = (u16)(phy_read(phy, 0x1a));
+ reg_short |= 0x8000; /* bypass Auto-Negotiation */
+ phy_write(phy, 0x1a, reg_short);
+ emac_mii_reset_phy(phy); /* reset MAC interface */
+
+ /* Reset access to Page 0 */
+ phy_write(phy, 0x16, 0x0000);
+
+ return 0;
+}
+
static int et1011c_init(struct mii_phy *phy)
{
u16 reg_short;
@@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = {
.ops = &m88e1111_phy_ops,
};
+static struct mii_phy_ops m88e1112_phy_ops = {
+ .init = m88e1112_init,
+ .setup_aneg = genmii_setup_aneg,
+ .setup_forced = genmii_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = genmii_read_link
+};
+
+static struct mii_phy_def m88e1112_phy_def = {
+ .phy_id = 0x01410C90,
+ .phy_id_mask = 0x0ffffff0,
+ .name = "Marvell 88E1112 Ethernet",
+ .ops = &m88e1112_phy_ops,
+};
+
static struct mii_phy_def *mii_phy_table[] = {
&et1011c_phy_def,
&cis8201_phy_def,
&bcm5248_phy_def,
&m88e1111_phy_def,
+ &m88e1112_phy_def,
&genmii_phy_def,
NULL
};
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h
index 1b65c81f655..5d2bf4cbe50 100644
--- a/drivers/net/ibm_newemac/phy.h
+++ b/drivers/net/ibm_newemac/phy.h
@@ -57,6 +57,7 @@ struct mii_phy {
or determined automaticaly */
int address; /* PHY address */
int mode; /* PHY mode */
+ int gpcs_address; /* GPCS PHY address */
/* 1: autoneg enabled, 0: disabled */
int autoneg;
@@ -81,5 +82,6 @@ struct mii_phy {
*/
int emac_mii_phy_probe(struct mii_phy *phy, int address);
int emac_mii_reset_phy(struct mii_phy *phy);
+int emac_mii_reset_gpcs(struct mii_phy *phy);
#endif /* __IBM_NEWEMAC_PHY_H */
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 95e3464068d..f02764725a2 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -71,7 +71,7 @@ History:
June 1st, 2000
corrected version codes, added support for the latest 2.3 changes
Oct 28th, 2002
- cleaned up for the 2.5 tree <alan@redhat.com>
+ cleaned up for the 2.5 tree <alan@lxorguk.ukuu.org.uk>
*************************************************************************/
diff --git a/drivers/net/jme.c b/drivers/net/jme.c
index 156f159aafb..81c6cdc3851 100644
--- a/drivers/net/jme.c
+++ b/drivers/net/jme.c
@@ -37,6 +37,7 @@
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/if_vlan.h>
+#include <net/ip6_checksum.h>
#include "jme.h"
static int force_pseudohp = -1;
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 51ad3765e07..85587a6667b 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -9,7 +9,7 @@
* 2 of the License, or (at your option) any later version.
*
* Copyright (C) 1996 Paul Mackerras.
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Modified heavily by Joshua M. Thompson based on Dave Huang's NetBSD driver
*
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 0b28d0d8ffa..c235cdba69c 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -15,7 +15,7 @@
incorporated herein by reference.
Donald Becker may be reached at becker@scyld.com
- Updated for 2.5.x by Alan Cox <alan@redhat.com>
+ Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk>
======================================================================*/
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 54df34f21c5..448cd40aeba 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -69,7 +69,7 @@ Driver Notes and Issues
History
-------------------------------------------------------------------------------
Log: nmclan_cs.c,v
- * 2.5.75-ac1 2003/07/11 Alan Cox <alan@redhat.com>
+ * 2.5.75-ac1 2003/07/11 Alan Cox <alan@lxorguk.ukuu.org.uk>
* Fixed hang on card eject as we probe it
* Cleaned up to use new style locking.
*
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 6671e2da0d5..d0ed1ef284a 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -55,6 +55,7 @@ EXPORT_SYMBOL(mdiobus_alloc);
/**
* mdiobus_release - mii_bus device release callback
+ * @d: the target struct device that contains the mii_bus
*
* Description: called when the last reference to an mii_bus is
* dropped, to free the underlying memory.
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 17162748005..f11e900b437 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -557,6 +557,7 @@ int genphy_restart_aneg(struct phy_device *phydev)
return ctl;
}
+EXPORT_SYMBOL(genphy_restart_aneg);
/**
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index c37ea436c91..38116f9d416 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -58,7 +58,7 @@
*/
#if (PAGE_SHIFT == 12) || (PAGE_SHIFT == 13) /* 4k & 8k pages */
#define TX_DESC_PER_OAL ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2)
-#elif (PAGE_SHIFT == 16) /* 64k pages */
+#else /* all other page sizes */
#define TX_DESC_PER_OAL 0
#endif
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 297877b68c4..4b2caa6b7ac 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -39,6 +39,7 @@
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
+#include <net/ip6_checksum.h>
#include "qlge.h"
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index ec871f64676..c41d6876136 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -29,7 +29,8 @@
*
* Tigran Aivazian <tigran@sco.com>: TLan_PciProbe() now uses
* new PCI BIOS interface.
- * Alan Cox <alan@redhat.com>: Fixed the out of memory
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ * Fixed the out of memory
* handling.
*
* Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index fa73e6eed6b..ed50d288e49 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -25,7 +25,7 @@
* To do:
* 1. Multicast support.
*
- * Initial 2.5 cleanup Alan Cox <alan@redhat.com> 2002/10/28
+ * Initial 2.5 cleanup Alan Cox <alan@lxorguk.ukuu.org.uk> 2002/10/28
*/
#include <linux/module.h>
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index f54c45049d5..124d5d690dd 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -1688,6 +1688,7 @@ static void __devinit de21040_get_mac_address (struct de_private *de)
unsigned i;
dw32 (ROMCmd, 0); /* Reset the pointer with a dummy write. */
+ udelay(5);
for (i = 0; i < 6; i++) {
int value, boguscnt = 100000;
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index 656200472fa..8e46a513a25 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -23,7 +23,7 @@
Marcelo Tosatti <marcelo@conectiva.com.br> :
Made it compile in 2.3 (device to net_device)
- Alan Cox <alan@redhat.com> :
+ Alan Cox <alan@lxorguk.ukuu.org.uk> :
Cleaned up for kernel merge.
Removed the back compatibility support
Reformatted, fixing spelling etc as I went
@@ -49,7 +49,7 @@
support. Updated PCI resource allocation. Do not
forget to unmap PCI mapped skbs.
- Alan Cox <alan@redhat.com>
+ Alan Cox <alan@lxorguk.ukuu.org.uk>
Added new PCI identifiers provided by Clear Zhang at ALi
for their 1563 ethernet device.
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index ad20f96edfa..2dced383bcf 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -12,7 +12,7 @@
* Scatter gather
* More testing
*
- * The changes are (c) Copyright 2004, Red Hat Inc. <alan@redhat.com>
+ * The changes are (c) Copyright 2004, Red Hat Inc. <alan@lxorguk.ukuu.org.uk>
* Additional fixes and clean up: Francois Romieu
*
* This source has not been verified for use in safety critical systems.
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index 243bd8d918f..ccd9cd35ecb 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -18,7 +18,8 @@
* DMA now uses get_free_page as kmalloc buffers may span a 64K
* boundary.
*
- * Modified for SMP safety and SMP locking by Alan Cox <alan@redhat.com>
+ * Modified for SMP safety and SMP locking by Alan Cox
+ * <alan@lxorguk.ukuu.org.uk>
*
* Performance
*
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index 4f372396c51..85b3e785d48 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -2,7 +2,7 @@
* Description of Z8530 Z85C30 and Z85230 communications chips
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1998 Alan Cox <alan@redhat.com>
+ * Copyright (C) 1998 Alan Cox <alan@lxorguk.ukuu.org.uk>
*/
#ifndef _Z8530_H
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 136220b5ca8..e939a73ff79 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -4387,7 +4387,7 @@ MODULE_LICENSE("GPL");
*
* Thanks go also to:
* James Ashton (jaa101@syseng.anu.edu.au),
- * Alan Cox (alan@redhat.com),
+ * Alan Cox (alan@lxorguk.ukuu.org.uk),
* Allan Creighton (allanc@cs.usyd.edu.au),
* Matthew Geier (matthew@cs.usyd.edu.au),
* Remo di Giovanni (remo@cs.usyd.edu.au),
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index b33ac47dd8d..44d31bbf39e 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -186,7 +186,7 @@
*
* Thanks go also to:
* James Ashton <jaa101@syseng.anu.edu.au>,
- * Alan Cox <alan@redhat.com>,
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>,
* Allan Creighton <allanc@cs.usyd.edu.au>,
* Matthew Geier <matthew@cs.usyd.edu.au>,
* Remo di Giovanni <remo@cs.usyd.edu.au>,
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index 3c3dd403f5d..5c7a87e3895 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -471,7 +471,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int offset = offset_in_page(data);
unsigned int len = skb_headlen(skb);
- frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
+ frags += DIV_ROUND_UP(offset + len, PAGE_SIZE);
if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
frags);
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 2f047e573d8..f5f75844954 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -126,7 +126,7 @@ static void nubus_advance(unsigned char **ptr, int len, int map)
{
while(not_useful(p,map))
p++;
- p++;
+ p++;
len--;
}
*ptr = p;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index ad8ac1a8af2..7c79e94a35e 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -410,7 +410,7 @@ struct of_modalias_table {
char *modalias;
};
static struct of_modalias_table of_modalias_table[] = {
- /* Empty for now; add entries as needed */
+ { "fsl,mcu-mpc8349emitx", "mcu-mpc8349emitx" },
};
/**
@@ -420,13 +420,12 @@ static struct of_modalias_table of_modalias_table[] = {
* @len: Length of modalias value
*
* Based on the value of the compatible property, this routine will determine
- * an appropriate modalias value for a particular device tree node. Three
- * separate methods are used to derive a modalias value.
+ * an appropriate modalias value for a particular device tree node. Two
+ * separate methods are attempted to derive a modalias value.
*
* First method is to lookup the compatible value in of_modalias_table.
- * Second is to look for a "linux,<modalias>" entry in the compatible list
- * and used that for modalias. Third is to strip off the manufacturer
- * prefix from the first compatible entry and use the remainder as modalias
+ * Second is to strip off the manufacturer prefix from the first
+ * compatible entry and use the remainder as modalias
*
* This routine returns 0 on success
*/
@@ -449,21 +448,7 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
if (!compatible)
return -ENODEV;
- /* 2. search for linux,<modalias> entry */
- p = compatible;
- while (cplen > 0) {
- if (!strncmp(p, "linux,", 6)) {
- p += 6;
- strlcpy(modalias, p, len);
- return 0;
- }
-
- i = strlen(p) + 1;
- p += i;
- cplen -= i;
- }
-
- /* 3. take first compatible entry and strip manufacturer */
+ /* 2. take first compatible entry and strip manufacturer */
p = strchr(compatible, ',');
if (!p)
return -ENODEV;
@@ -473,3 +458,112 @@ int of_modalias_node(struct device_node *node, char *modalias, int len)
}
EXPORT_SYMBOL_GPL(of_modalias_node);
+/**
+ * of_parse_phandles_with_args - Find a node pointed by phandle in a list
+ * @np: pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name: property name that specifies phandles' arguments count
+ * @index: index of a phandle to parse out
+ * @out_node: pointer to device_node struct pointer (will be filled)
+ * @out_args: pointer to arguments pointer (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_node and out_args, on error returns
+ * appropriate errno value.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ * #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ * list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandles_with_args(node3, "list", "#list-cells", 2, &node2, &args);
+ */
+int of_parse_phandles_with_args(struct device_node *np, const char *list_name,
+ const char *cells_name, int index,
+ struct device_node **out_node,
+ const void **out_args)
+{
+ int ret = -EINVAL;
+ const u32 *list;
+ const u32 *list_end;
+ int size;
+ int cur_index = 0;
+ struct device_node *node = NULL;
+ const void *args;
+
+ list = of_get_property(np, list_name, &size);
+ if (!list) {
+ ret = -ENOENT;
+ goto err0;
+ }
+ list_end = list + size / sizeof(*list);
+
+ while (list < list_end) {
+ const u32 *cells;
+ const phandle *phandle;
+
+ phandle = list;
+ args = list + 1;
+
+ /* one cell hole in the list = <>; */
+ if (!*phandle) {
+ list++;
+ goto next;
+ }
+
+ node = of_find_node_by_phandle(*phandle);
+ if (!node) {
+ pr_debug("%s: could not find phandle\n",
+ np->full_name);
+ goto err0;
+ }
+
+ cells = of_get_property(node, cells_name, &size);
+ if (!cells || size != sizeof(*cells)) {
+ pr_debug("%s: could not get %s for %s\n",
+ np->full_name, cells_name, node->full_name);
+ goto err1;
+ }
+
+ /* Next phandle is at offset of one phandle cell + #cells */
+ list += 1 + *cells;
+ if (list > list_end) {
+ pr_debug("%s: insufficient arguments length\n",
+ np->full_name);
+ goto err1;
+ }
+next:
+ if (cur_index == index)
+ break;
+
+ of_node_put(node);
+ node = NULL;
+ cur_index++;
+ }
+
+ if (!node) {
+ ret = -ENOENT;
+ goto err0;
+ }
+
+ *out_node = node;
+ *out_args = args;
+
+ return 0;
+err1:
+ of_node_put(node);
+err0:
+ pr_debug("%s failed with status %d\n", __func__, ret);
+ return ret;
+}
+EXPORT_SYMBOL(of_parse_phandles_with_args);
diff --git a/drivers/of/gpio.c b/drivers/of/gpio.c
index 1c9cab844f1..7cd7301b583 100644
--- a/drivers/of/gpio.c
+++ b/drivers/of/gpio.c
@@ -28,78 +28,35 @@
*/
int of_get_gpio(struct device_node *np, int index)
{
- int ret = -EINVAL;
+ int ret;
struct device_node *gc;
struct of_gpio_chip *of_gc = NULL;
int size;
- const u32 *gpios;
- u32 nr_cells;
- int i;
const void *gpio_spec;
const u32 *gpio_cells;
- int gpio_index = 0;
- gpios = of_get_property(np, "gpios", &size);
- if (!gpios) {
- ret = -ENOENT;
+ ret = of_parse_phandles_with_args(np, "gpios", "#gpio-cells", index,
+ &gc, &gpio_spec);
+ if (ret) {
+ pr_debug("%s: can't parse gpios property\n", __func__);
goto err0;
}
- nr_cells = size / sizeof(u32);
-
- for (i = 0; i < nr_cells; gpio_index++) {
- const phandle *gpio_phandle;
-
- gpio_phandle = gpios + i;
- gpio_spec = gpio_phandle + 1;
-
- /* one cell hole in the gpios = <>; */
- if (!*gpio_phandle) {
- if (gpio_index == index)
- return -ENOENT;
- i++;
- continue;
- }
-
- gc = of_find_node_by_phandle(*gpio_phandle);
- if (!gc) {
- pr_debug("%s: could not find phandle for gpios\n",
- np->full_name);
- goto err0;
- }
-
- of_gc = gc->data;
- if (!of_gc) {
- pr_debug("%s: gpio controller %s isn't registered\n",
- np->full_name, gc->full_name);
- goto err1;
- }
-
- gpio_cells = of_get_property(gc, "#gpio-cells", &size);
- if (!gpio_cells || size != sizeof(*gpio_cells) ||
- *gpio_cells != of_gc->gpio_cells) {
- pr_debug("%s: wrong #gpio-cells for %s\n",
- np->full_name, gc->full_name);
- goto err1;
- }
-
- /* Next phandle is at phandle cells + #gpio-cells */
- i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
- if (i >= nr_cells + 1) {
- pr_debug("%s: insufficient gpio-spec length\n",
- np->full_name);
- goto err1;
- }
-
- if (gpio_index == index)
- break;
-
- of_gc = NULL;
- of_node_put(gc);
- }
+ of_gc = gc->data;
if (!of_gc) {
- ret = -ENOENT;
- goto err0;
+ pr_debug("%s: gpio controller %s isn't registered\n",
+ np->full_name, gc->full_name);
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+ if (!gpio_cells || size != sizeof(*gpio_cells) ||
+ *gpio_cells != of_gc->gpio_cells) {
+ pr_debug("%s: wrong #gpio-cells for %s\n",
+ np->full_name, gc->full_name);
+ ret = -EINVAL;
+ goto err1;
}
ret = of_gc->xlate(of_gc, np, gpio_spec);
diff --git a/drivers/parport/ChangeLog b/drivers/parport/ChangeLog
index db717c1d62a..8565bbbeb6e 100644
--- a/drivers/parport/ChangeLog
+++ b/drivers/parport/ChangeLog
@@ -311,7 +311,7 @@
* ieee1284_ops.c (parport_ieee1284_read_nibble): Reset nAutoFd
on timeout. Matches 2.2.x behaviour.
-2001-03-02 Andrew Morton <andrewm@uow.edu.au>
+2001-03-02 Andrew Morton
* parport_pc.c (registered_parport): New static variable.
(parport_pc_find_ports): Set it when we register PCI driver.
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index e97059415ab..ac2a805ac7e 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -1,4 +1,4 @@
-/* $Id: parport_ieee1284.c,v 1.4 1997/10/19 21:37:21 philip Exp $
+/*
* IEEE-1284 implementation for parport.
*
* Authors: Phil Blundell <philb@gnu.org>
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index cd565bb4e1a..0f6550719bc 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -1,4 +1,4 @@
-/* $Id: parport_probe.c,v 1.1 1999/07/03 08:56:17 davem Exp $
+/*
* Parallel port device probing code
*
* Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index a8a62bbbb57..0ebca450ed2 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.15 1998/01/11 12:06:17 philip Exp $
+/*
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
diff --git a/drivers/pci/hotplug/rpaphp_slot.c b/drivers/pci/hotplug/rpaphp_slot.c
index 9b714ea93d2..50884507b8b 100644
--- a/drivers/pci/hotplug/rpaphp_slot.c
+++ b/drivers/pci/hotplug/rpaphp_slot.c
@@ -147,9 +147,5 @@ int rpaphp_register_slot(struct slot *slot)
list_add(&slot->rpaphp_slot_list, &rpaphp_slot_head);
info("Slot [%s] registered\n", slot->name);
return 0;
-
-sysfs_fail:
- pci_hp_deregister(php_slot);
- return retval;
}
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 9fd7bb9b7dc..7cc7bf5304a 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -147,7 +147,7 @@ char *pnp_resource_type_name(struct resource *res);
void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
void pnp_free_resources(struct pnp_dev *dev);
-int pnp_resource_type(struct resource *res);
+unsigned long pnp_resource_type(struct resource *res);
struct pnp_resource {
struct list_head list;
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index a411582bcd7..cc0aeaed617 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -218,7 +218,6 @@ void __pnp_remove_device(struct pnp_dev *dev)
static int __init pnp_init(void)
{
- printk(KERN_INFO "Linux Plug and Play Support v0.97 (c) Adam Belay\n");
return bus_register(&pnp_bus_type);
}
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 101a835e875..46455fbab6d 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -1012,7 +1012,7 @@ static int __init isapnp_init(void)
printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
return 0;
}
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))
return -EINVAL;
#endif
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 662dfcddedc..2bfe13369df 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -519,7 +519,7 @@ static int __init pnpbios_init(void)
{
int ret;
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
if (check_legacy_ioport(PNPBIOS_BASE))
return -ENODEV;
#endif
@@ -577,7 +577,7 @@ static int __init pnpbios_thread_init(void)
{
struct task_struct *task;
-#if defined(CONFIG_PPC_MERGE)
+#if defined(CONFIG_PPC)
if (check_legacy_ioport(PNPBIOS_BASE))
return 0;
#endif
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index 0bdf9b8a5e5..d15e2b77af8 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -245,7 +245,7 @@ static void quirk_system_pci_resources(struct pnp_dev *dev)
*/
for_each_pci_dev(pdev) {
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
- unsigned int type;
+ unsigned long type;
type = pci_resource_flags(pdev, i) &
(IORESOURCE_IO | IORESOURCE_MEM);
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 4cfe3a1efdf..dbae23acdd5 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -467,14 +467,14 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
#endif
}
-int pnp_resource_type(struct resource *res)
+unsigned long pnp_resource_type(struct resource *res)
{
return res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
IORESOURCE_IRQ | IORESOURCE_DMA);
}
struct resource *pnp_get_resource(struct pnp_dev *dev,
- unsigned int type, unsigned int num)
+ unsigned long type, unsigned int num)
{
struct pnp_resource *pnp_res;
struct resource *res;
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index 32570af3c5c..5fbca2681ba 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -205,9 +205,9 @@ static int olpc_bat_get_property(struct power_supply *psy,
union power_supply_propval *val)
{
int ret = 0;
- int16_t ec_word;
+ __be16 ec_word;
uint8_t ec_byte;
- uint64_t ser_buf;
+ __be64 ser_buf;
ret = olpc_ec_cmd(EC_BAT_STATUS, NULL, 0, &ec_byte, 1);
if (ret)
@@ -257,16 +257,14 @@ static int olpc_bat_get_property(struct power_supply *psy,
if (ret)
return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 9760L / 32;
+ val->intval = (int)be16_to_cpu(ec_word) * 9760L / 32;
break;
case POWER_SUPPLY_PROP_CURRENT_AVG:
ret = olpc_ec_cmd(EC_BAT_CURRENT, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 15625L / 120;
+ val->intval = (int)be16_to_cpu(ec_word) * 15625L / 120;
break;
case POWER_SUPPLY_PROP_CAPACITY:
ret = olpc_ec_cmd(EC_BAT_SOC, NULL, 0, &ec_byte, 1);
@@ -278,24 +276,22 @@ static int olpc_bat_get_property(struct power_supply *psy,
ret = olpc_ec_cmd(EC_BAT_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 100 / 256;
+
+ val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
break;
case POWER_SUPPLY_PROP_TEMP_AMBIENT:
ret = olpc_ec_cmd(EC_AMB_TEMP, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 100 / 256;
+ val->intval = (int)be16_to_cpu(ec_word) * 100 / 256;
break;
case POWER_SUPPLY_PROP_CHARGE_COUNTER:
ret = olpc_ec_cmd(EC_BAT_ACR, NULL, 0, (void *)&ec_word, 2);
if (ret)
return ret;
- ec_word = be16_to_cpu(ec_word);
- val->intval = ec_word * 6250 / 15;
+ val->intval = (int)be16_to_cpu(ec_word) * 6250 / 15;
break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
ret = olpc_ec_cmd(EC_BAT_SERIAL, NULL, 0, (void *)&ser_buf, 8);
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index a656128f1fd..4dada6ee111 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -56,4 +56,28 @@ config REGULATOR_BQ24022
charging select between 100 mA and 500 mA charging current
limit.
+config REGULATOR_WM8350
+ tristate "Wolfson Microelectroncis WM8350 AudioPlus PMIC"
+ depends on MFD_WM8350
+ select REGULATOR
+ help
+ This driver provides support for the voltage and current regulators
+ of the WM8350 AudioPlus PMIC.
+
+config REGULATOR_WM8400
+ tristate "Wolfson Microelectroncis WM8400 AudioPlus PMIC"
+ depends on MFD_WM8400
+ select REGULATOR
+ help
+ This driver provides support for the voltage regulators of the
+ WM8400 AudioPlus PMIC.
+
+config REGULATOR_DA903X
+ tristate "Support regulators on Dialog Semiconductor DA9030/DA9034 PMIC"
+ depends on PMIC_DA903X
+ select REGULATOR
+ help
+ Say y here to support the BUCKs and LDOs regulators found on
+ Dialog Semiconductor DA9030/DA9034 PMIC.
+
endmenu
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index ac2c64efe65..254d40c02ee 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -8,5 +8,8 @@ obj-$(CONFIG_REGULATOR_FIXED_VOLTAGE) += fixed.o
obj-$(CONFIG_REGULATOR_VIRTUAL_CONSUMER) += virtual.o
obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o
+obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o
+obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o
+obj-$(CONFIG_REGULATOR_DA903X) += da903x.o
ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG
diff --git a/drivers/regulator/bq24022.c b/drivers/regulator/bq24022.c
index 263699d6152..366565aba86 100644
--- a/drivers/regulator/bq24022.c
+++ b/drivers/regulator/bq24022.c
@@ -18,13 +18,13 @@
#include <linux/regulator/bq24022.h>
#include <linux/regulator/driver.h>
+
static int bq24022_set_current_limit(struct regulator_dev *rdev,
int min_uA, int max_uA)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "setting current limit to %s mA\n",
+ dev_dbg(rdev_get_dev(rdev), "setting current limit to %s mA\n",
max_uA >= 500000 ? "500" : "100");
/* REVISIT: maybe return error if min_uA != 0 ? */
@@ -34,18 +34,16 @@ static int bq24022_set_current_limit(struct regulator_dev *rdev,
static int bq24022_get_current_limit(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
return gpio_get_value(pdata->gpio_iset2) ? 500000 : 100000;
}
static int bq24022_enable(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "enabling charger\n");
+ dev_dbg(rdev_get_dev(rdev), "enabling charger\n");
gpio_set_value(pdata->gpio_nce, 0);
return 0;
@@ -53,10 +51,9 @@ static int bq24022_enable(struct regulator_dev *rdev)
static int bq24022_disable(struct regulator_dev *rdev)
{
- struct platform_device *pdev = rdev_get_drvdata(rdev);
- struct bq24022_mach_info *pdata = pdev->dev.platform_data;
+ struct bq24022_mach_info *pdata = rdev_get_drvdata(rdev);
- dev_dbg(&pdev->dev, "disabling charger\n");
+ dev_dbg(rdev_get_dev(rdev), "disabling charger\n");
gpio_set_value(pdata->gpio_nce, 1);
return 0;
@@ -108,7 +105,7 @@ static int __init bq24022_probe(struct platform_device *pdev)
ret = gpio_direction_output(pdata->gpio_iset2, 0);
ret = gpio_direction_output(pdata->gpio_nce, 1);
- bq24022 = regulator_register(&bq24022_desc, pdev);
+ bq24022 = regulator_register(&bq24022_desc, &pdev->dev, pdata);
if (IS_ERR(bq24022)) {
dev_dbg(&pdev->dev, "couldn't register regulator\n");
ret = PTR_ERR(bq24022);
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9c798626156..02a774424e8 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -2,8 +2,9 @@
* core.c -- Voltage/Current Regulator framework.
*
* Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ * Copyright 2008 SlimLogic Ltd.
*
- * Author: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -64,14 +65,9 @@ struct regulator_map {
struct list_head list;
struct device *dev;
const char *supply;
- const char *regulator;
+ struct regulator_dev *regulator;
};
-static inline struct regulator_dev *to_rdev(struct device *d)
-{
- return container_of(d, struct regulator_dev, dev);
-}
-
/*
* struct regulator
*
@@ -227,7 +223,7 @@ static ssize_t device_requested_uA_show(struct device *dev,
static ssize_t regulator_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
ssize_t ret;
mutex_lock(&rdev->mutex);
@@ -240,15 +236,31 @@ static ssize_t regulator_uV_show(struct device *dev,
static ssize_t regulator_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev));
}
+static ssize_t regulator_name_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ const char *name;
+
+ if (rdev->constraints->name)
+ name = rdev->constraints->name;
+ else if (rdev->desc->name)
+ name = rdev->desc->name;
+ else
+ name = "";
+
+ return sprintf(buf, "%s\n", name);
+}
+
static ssize_t regulator_opmode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
int mode = _regulator_get_mode(rdev);
switch (mode) {
@@ -267,7 +279,7 @@ static ssize_t regulator_opmode_show(struct device *dev,
static ssize_t regulator_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
int state = _regulator_is_enabled(rdev);
if (state > 0)
@@ -281,7 +293,7 @@ static ssize_t regulator_state_show(struct device *dev,
static ssize_t regulator_min_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -292,7 +304,7 @@ static ssize_t regulator_min_uA_show(struct device *dev,
static ssize_t regulator_max_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -303,7 +315,7 @@ static ssize_t regulator_max_uA_show(struct device *dev,
static ssize_t regulator_min_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -314,7 +326,7 @@ static ssize_t regulator_min_uV_show(struct device *dev,
static ssize_t regulator_max_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "constraint not defined\n");
@@ -325,7 +337,7 @@ static ssize_t regulator_max_uV_show(struct device *dev,
static ssize_t regulator_total_uA_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
struct regulator *regulator;
int uA = 0;
@@ -339,14 +351,14 @@ static ssize_t regulator_total_uA_show(struct device *dev,
static ssize_t regulator_num_users_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", rdev->use_count);
}
static ssize_t regulator_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
switch (rdev->desc->type) {
case REGULATOR_VOLTAGE:
@@ -360,7 +372,7 @@ static ssize_t regulator_type_show(struct device *dev,
static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -370,7 +382,7 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev,
static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -380,7 +392,7 @@ static ssize_t regulator_suspend_disk_uV_show(struct device *dev,
static ssize_t regulator_suspend_standby_uV_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -406,7 +418,7 @@ static ssize_t suspend_opmode_show(struct regulator_dev *rdev,
static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -417,7 +429,7 @@ static ssize_t regulator_suspend_mem_mode_show(struct device *dev,
static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -428,7 +440,7 @@ static ssize_t regulator_suspend_disk_mode_show(struct device *dev,
static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -439,7 +451,7 @@ static ssize_t regulator_suspend_standby_mode_show(struct device *dev,
static ssize_t regulator_suspend_mem_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -453,7 +465,7 @@ static ssize_t regulator_suspend_mem_state_show(struct device *dev,
static ssize_t regulator_suspend_disk_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -467,7 +479,7 @@ static ssize_t regulator_suspend_disk_state_show(struct device *dev,
static ssize_t regulator_suspend_standby_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
if (!rdev->constraints)
return sprintf(buf, "not defined\n");
@@ -477,7 +489,9 @@ static ssize_t regulator_suspend_standby_state_show(struct device *dev,
else
return sprintf(buf, "disabled\n");
}
+
static struct device_attribute regulator_dev_attrs[] = {
+ __ATTR(name, 0444, regulator_name_show, NULL),
__ATTR(microvolts, 0444, regulator_uV_show, NULL),
__ATTR(microamps, 0444, regulator_uA_show, NULL),
__ATTR(opmode, 0444, regulator_opmode_show, NULL),
@@ -512,7 +526,7 @@ static struct device_attribute regulator_dev_attrs[] = {
static void regulator_dev_release(struct device *dev)
{
- struct regulator_dev *rdev = to_rdev(dev);
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
kfree(rdev);
}
@@ -569,8 +583,11 @@ static int suspend_set_state(struct regulator_dev *rdev,
/* enable & disable are mandatory for suspend control */
if (!rdev->desc->ops->set_suspend_enable ||
- !rdev->desc->ops->set_suspend_disable)
+ !rdev->desc->ops->set_suspend_disable) {
+ printk(KERN_ERR "%s: no way to set suspend state\n",
+ __func__);
return -EINVAL;
+ }
if (rstate->enabled)
ret = rdev->desc->ops->set_suspend_enable(rdev);
@@ -656,6 +673,155 @@ static void print_constraints(struct regulator_dev *rdev)
printk(KERN_INFO "regulator: %s: %s\n", rdev->desc->name, buf);
}
+/**
+ * set_machine_constraints - sets regulator constraints
+ * @regulator: regulator source
+ *
+ * Allows platform initialisation code to define and constrain
+ * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
+ * Constraints *must* be set by platform code in order for some
+ * regulator operations to proceed i.e. set_voltage, set_current_limit,
+ * set_mode.
+ */
+static int set_machine_constraints(struct regulator_dev *rdev,
+ struct regulation_constraints *constraints)
+{
+ int ret = 0;
+ const char *name;
+ struct regulator_ops *ops = rdev->desc->ops;
+
+ if (constraints->name)
+ name = constraints->name;
+ else if (rdev->desc->name)
+ name = rdev->desc->name;
+ else
+ name = "regulator";
+
+ rdev->constraints = constraints;
+
+ /* do we need to apply the constraint voltage */
+ if (rdev->constraints->apply_uV &&
+ rdev->constraints->min_uV == rdev->constraints->max_uV &&
+ ops->set_voltage) {
+ ret = ops->set_voltage(rdev,
+ rdev->constraints->min_uV, rdev->constraints->max_uV);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to apply %duV constraint to %s\n",
+ __func__,
+ rdev->constraints->min_uV, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ /* are we enabled at boot time by firmware / bootloader */
+ if (rdev->constraints->boot_on)
+ rdev->use_count = 1;
+
+ /* do we need to setup our suspend state */
+ if (constraints->initial_state) {
+ ret = suspend_prepare(rdev, constraints->initial_state);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to set suspend state for %s\n",
+ __func__, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ /* if always_on is set then turn the regulator on if it's not
+ * already on. */
+ if (constraints->always_on && ops->enable &&
+ ((ops->is_enabled && !ops->is_enabled(rdev)) ||
+ (!ops->is_enabled && !constraints->boot_on))) {
+ ret = ops->enable(rdev);
+ if (ret < 0) {
+ printk(KERN_ERR "%s: failed to enable %s\n",
+ __func__, name);
+ rdev->constraints = NULL;
+ goto out;
+ }
+ }
+
+ print_constraints(rdev);
+out:
+ return ret;
+}
+
+/**
+ * set_supply - set regulator supply regulator
+ * @regulator: regulator name
+ * @supply: supply regulator name
+ *
+ * Called by platform initialisation code to set the supply regulator for this
+ * regulator. This ensures that a regulators supply will also be enabled by the
+ * core if it's child is enabled.
+ */
+static int set_supply(struct regulator_dev *rdev,
+ struct regulator_dev *supply_rdev)
+{
+ int err;
+
+ err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
+ "supply");
+ if (err) {
+ printk(KERN_ERR
+ "%s: could not add device link %s err %d\n",
+ __func__, supply_rdev->dev.kobj.name, err);
+ goto out;
+ }
+ rdev->supply = supply_rdev;
+ list_add(&rdev->slist, &supply_rdev->supply_list);
+out:
+ return err;
+}
+
+/**
+ * set_consumer_device_supply: Bind a regulator to a symbolic supply
+ * @regulator: regulator source
+ * @dev: device the supply applies to
+ * @supply: symbolic name for supply
+ *
+ * Allows platform initialisation code to map physical regulator
+ * sources to symbolic names for supplies for use by devices. Devices
+ * should use these symbolic names to request regulators, avoiding the
+ * need to provide board-specific regulator names as platform data.
+ */
+static int set_consumer_device_supply(struct regulator_dev *rdev,
+ struct device *consumer_dev, const char *supply)
+{
+ struct regulator_map *node;
+
+ if (supply == NULL)
+ return -EINVAL;
+
+ node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->regulator = rdev;
+ node->dev = consumer_dev;
+ node->supply = supply;
+
+ list_add(&node->list, &regulator_map_list);
+ return 0;
+}
+
+static void unset_consumer_device_supply(struct regulator_dev *rdev,
+ struct device *consumer_dev)
+{
+ struct regulator_map *node, *n;
+
+ list_for_each_entry_safe(node, n, &regulator_map_list, list) {
+ if (rdev == node->regulator &&
+ consumer_dev == node->dev) {
+ list_del(&node->list);
+ kfree(node);
+ return;
+ }
+ }
+}
+
#define REG_STR_SIZE 32
static struct regulator *create_regulator(struct regulator_dev *rdev,
@@ -746,7 +912,6 @@ struct regulator *regulator_get(struct device *dev, const char *id)
struct regulator_dev *rdev;
struct regulator_map *map;
struct regulator *regulator = ERR_PTR(-ENODEV);
- const char *supply = id;
if (id == NULL) {
printk(KERN_ERR "regulator: get() with no identifier\n");
@@ -758,15 +923,9 @@ struct regulator *regulator_get(struct device *dev, const char *id)
list_for_each_entry(map, &regulator_map_list, list) {
if (dev == map->dev &&
strcmp(map->supply, id) == 0) {
- supply = map->regulator;
- break;
- }
- }
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (strcmp(supply, rdev->desc->name) == 0 &&
- try_module_get(rdev->owner))
+ rdev = map->regulator;
goto found;
+ }
}
printk(KERN_ERR "regulator: Unable to get requested regulator: %s\n",
id);
@@ -774,12 +933,16 @@ struct regulator *regulator_get(struct device *dev, const char *id)
return regulator;
found:
+ if (!try_module_get(rdev->owner))
+ goto out;
+
regulator = create_regulator(rdev, dev, id);
if (regulator == NULL) {
regulator = ERR_PTR(-ENOMEM);
module_put(rdev->owner);
}
+out:
mutex_unlock(&regulator_list_mutex);
return regulator;
}
@@ -1559,11 +1722,12 @@ EXPORT_SYMBOL_GPL(regulator_notifier_call_chain);
* Returns 0 on success.
*/
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- void *reg_data)
+ struct device *dev, void *driver_data)
{
static atomic_t regulator_no = ATOMIC_INIT(0);
struct regulator_dev *rdev;
- int ret;
+ struct regulator_init_data *init_data = dev->platform_data;
+ int ret, i;
if (regulator_desc == NULL)
return ERR_PTR(-EINVAL);
@@ -1575,6 +1739,9 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
!regulator_desc->type == REGULATOR_CURRENT)
return ERR_PTR(-EINVAL);
+ if (!init_data)
+ return ERR_PTR(-EINVAL);
+
rdev = kzalloc(sizeof(struct regulator_dev), GFP_KERNEL);
if (rdev == NULL)
return ERR_PTR(-ENOMEM);
@@ -1582,7 +1749,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
mutex_lock(&regulator_list_mutex);
mutex_init(&rdev->mutex);
- rdev->reg_data = reg_data;
+ rdev->reg_data = driver_data;
rdev->owner = regulator_desc->owner;
rdev->desc = regulator_desc;
INIT_LIST_HEAD(&rdev->consumer_list);
@@ -1591,20 +1758,68 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
INIT_LIST_HEAD(&rdev->slist);
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
+ /* preform any regulator specific init */
+ if (init_data->regulator_init) {
+ ret = init_data->regulator_init(rdev->reg_data);
+ if (ret < 0) {
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+ }
+
+ /* set regulator constraints */
+ ret = set_machine_constraints(rdev, &init_data->constraints);
+ if (ret < 0) {
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+
+ /* register with sysfs */
rdev->dev.class = &regulator_class;
- device_initialize(&rdev->dev);
+ rdev->dev.parent = dev;
snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id),
- "regulator_%ld_%s",
- (unsigned long)atomic_inc_return(&regulator_no) - 1,
- regulator_desc->name);
-
- ret = device_add(&rdev->dev);
- if (ret == 0)
- list_add(&rdev->list, &regulator_list);
- else {
+ "regulator.%d", atomic_inc_return(&regulator_no) - 1);
+ ret = device_register(&rdev->dev);
+ if (ret != 0) {
kfree(rdev);
rdev = ERR_PTR(ret);
+ goto out;
+ }
+
+ dev_set_drvdata(&rdev->dev, rdev);
+
+ /* set supply regulator if it exists */
+ if (init_data->supply_regulator_dev) {
+ ret = set_supply(rdev,
+ dev_get_drvdata(init_data->supply_regulator_dev));
+ if (ret < 0) {
+ device_unregister(&rdev->dev);
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
}
+
+ /* add consumers devices */
+ for (i = 0; i < init_data->num_consumer_supplies; i++) {
+ ret = set_consumer_device_supply(rdev,
+ init_data->consumer_supplies[i].dev,
+ init_data->consumer_supplies[i].supply);
+ if (ret < 0) {
+ for (--i; i >= 0; i--)
+ unset_consumer_device_supply(rdev,
+ init_data->consumer_supplies[i].dev);
+ device_unregister(&rdev->dev);
+ kfree(rdev);
+ rdev = ERR_PTR(ret);
+ goto out;
+ }
+ }
+
+ list_add(&rdev->list, &regulator_list);
+out:
mutex_unlock(&regulator_list_mutex);
return rdev;
}
@@ -1631,187 +1846,6 @@ void regulator_unregister(struct regulator_dev *rdev)
EXPORT_SYMBOL_GPL(regulator_unregister);
/**
- * regulator_set_supply - set regulator supply regulator
- * @regulator: regulator name
- * @supply: supply regulator name
- *
- * Called by platform initialisation code to set the supply regulator for this
- * regulator. This ensures that a regulators supply will also be enabled by the
- * core if it's child is enabled.
- */
-int regulator_set_supply(const char *regulator, const char *supply)
-{
- struct regulator_dev *rdev, *supply_rdev;
- int err;
-
- if (regulator == NULL || supply == NULL)
- return -EINVAL;
-
- mutex_lock(&regulator_list_mutex);
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(rdev->desc->name, regulator))
- goto found_regulator;
- }
- mutex_unlock(&regulator_list_mutex);
- return -ENODEV;
-
-found_regulator:
- list_for_each_entry(supply_rdev, &regulator_list, list) {
- if (!strcmp(supply_rdev->desc->name, supply))
- goto found_supply;
- }
- mutex_unlock(&regulator_list_mutex);
- return -ENODEV;
-
-found_supply:
- err = sysfs_create_link(&rdev->dev.kobj, &supply_rdev->dev.kobj,
- "supply");
- if (err) {
- printk(KERN_ERR
- "%s: could not add device link %s err %d\n",
- __func__, supply_rdev->dev.kobj.name, err);
- goto out;
- }
- rdev->supply = supply_rdev;
- list_add(&rdev->slist, &supply_rdev->supply_list);
-out:
- mutex_unlock(&regulator_list_mutex);
- return err;
-}
-EXPORT_SYMBOL_GPL(regulator_set_supply);
-
-/**
- * regulator_get_supply - get regulator supply regulator
- * @regulator: regulator name
- *
- * Returns the supply supply regulator name or NULL if no supply regulator
- * exists (i.e the regulator is supplied directly from USB, Line, Battery, etc)
- */
-const char *regulator_get_supply(const char *regulator)
-{
- struct regulator_dev *rdev;
-
- if (regulator == NULL)
- return NULL;
-
- mutex_lock(&regulator_list_mutex);
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(rdev->desc->name, regulator))
- goto found;
- }
- mutex_unlock(&regulator_list_mutex);
- return NULL;
-
-found:
- mutex_unlock(&regulator_list_mutex);
- if (rdev->supply)
- return rdev->supply->desc->name;
- else
- return NULL;
-}
-EXPORT_SYMBOL_GPL(regulator_get_supply);
-
-/**
- * regulator_set_machine_constraints - sets regulator constraints
- * @regulator: regulator source
- *
- * Allows platform initialisation code to define and constrain
- * regulator circuits e.g. valid voltage/current ranges, etc. NOTE:
- * Constraints *must* be set by platform code in order for some
- * regulator operations to proceed i.e. set_voltage, set_current_limit,
- * set_mode.
- */
-int regulator_set_machine_constraints(const char *regulator_name,
- struct regulation_constraints *constraints)
-{
- struct regulator_dev *rdev;
- int ret = 0;
-
- if (regulator_name == NULL)
- return -EINVAL;
-
- mutex_lock(&regulator_list_mutex);
-
- list_for_each_entry(rdev, &regulator_list, list) {
- if (!strcmp(regulator_name, rdev->desc->name))
- goto found;
- }
- ret = -ENODEV;
- goto out;
-
-found:
- mutex_lock(&rdev->mutex);
- rdev->constraints = constraints;
-
- /* do we need to apply the constraint voltage */
- if (rdev->constraints->apply_uV &&
- rdev->constraints->min_uV == rdev->constraints->max_uV &&
- rdev->desc->ops->set_voltage) {
- ret = rdev->desc->ops->set_voltage(rdev,
- rdev->constraints->min_uV, rdev->constraints->max_uV);
- if (ret < 0) {
- printk(KERN_ERR "%s: failed to apply %duV"
- " constraint\n", __func__,
- rdev->constraints->min_uV);
- rdev->constraints = NULL;
- goto out;
- }
- }
-
- /* are we enabled at boot time by firmware / bootloader */
- if (rdev->constraints->boot_on)
- rdev->use_count = 1;
-
- /* do we need to setup our suspend state */
- if (constraints->initial_state)
- ret = suspend_prepare(rdev, constraints->initial_state);
-
- print_constraints(rdev);
- mutex_unlock(&rdev->mutex);
-
-out:
- mutex_unlock(&regulator_list_mutex);
- return ret;
-}
-EXPORT_SYMBOL_GPL(regulator_set_machine_constraints);
-
-
-/**
- * regulator_set_device_supply: Bind a regulator to a symbolic supply
- * @regulator: regulator source
- * @dev: device the supply applies to
- * @supply: symbolic name for supply
- *
- * Allows platform initialisation code to map physical regulator
- * sources to symbolic names for supplies for use by devices. Devices
- * should use these symbolic names to request regulators, avoiding the
- * need to provide board-specific regulator names as platform data.
- */
-int regulator_set_device_supply(const char *regulator, struct device *dev,
- const char *supply)
-{
- struct regulator_map *node;
-
- if (regulator == NULL || supply == NULL)
- return -EINVAL;
-
- node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL);
- if (node == NULL)
- return -ENOMEM;
-
- node->regulator = regulator;
- node->dev = dev;
- node->supply = supply;
-
- mutex_lock(&regulator_list_mutex);
- list_add(&node->list, &regulator_map_list);
- mutex_unlock(&regulator_list_mutex);
- return 0;
-}
-EXPORT_SYMBOL_GPL(regulator_set_device_supply);
-
-/**
* regulator_suspend_prepare: prepare regulators for system wide suspend
* @state: system suspend state
*
@@ -1893,6 +1927,18 @@ int rdev_get_id(struct regulator_dev *rdev)
}
EXPORT_SYMBOL_GPL(rdev_get_id);
+struct device *rdev_get_dev(struct regulator_dev *rdev)
+{
+ return &rdev->dev;
+}
+EXPORT_SYMBOL_GPL(rdev_get_dev);
+
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data)
+{
+ return reg_init_data->driver_data;
+}
+EXPORT_SYMBOL_GPL(regulator_get_init_drvdata);
+
static int __init regulator_init(void)
{
printk(KERN_INFO "regulator: core version %s\n", REGULATOR_VERSION);
diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c
new file mode 100644
index 00000000000..3688e339db8
--- /dev/null
+++ b/drivers/regulator/da903x.c
@@ -0,0 +1,513 @@
+/*
+ * Regulators driver for Dialog Semiconductor DA903x
+ *
+ * Copyright (C) 2006-2008 Marvell International Ltd.
+ * Copyright (C) 2008 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/da903x.h>
+
+/* DA9030 Registers */
+#define DA9030_INVAL (-1)
+#define DA9030_LDO1011 (0x10)
+#define DA9030_LDO15 (0x11)
+#define DA9030_LDO1416 (0x12)
+#define DA9030_LDO1819 (0x13)
+#define DA9030_LDO17 (0x14)
+#define DA9030_BUCK2DVM1 (0x15)
+#define DA9030_BUCK2DVM2 (0x16)
+#define DA9030_RCTL11 (0x17)
+#define DA9030_RCTL21 (0x18)
+#define DA9030_LDO1 (0x90)
+#define DA9030_LDO23 (0x91)
+#define DA9030_LDO45 (0x92)
+#define DA9030_LDO6 (0x93)
+#define DA9030_LDO78 (0x94)
+#define DA9030_LDO912 (0x95)
+#define DA9030_BUCK (0x96)
+#define DA9030_RCTL12 (0x97)
+#define DA9030_RCTL22 (0x98)
+#define DA9030_LDO_UNLOCK (0xa0)
+#define DA9030_LDO_UNLOCK_MASK (0xe0)
+#define DA9034_OVER1 (0x10)
+
+/* DA9034 Registers */
+#define DA9034_INVAL (-1)
+#define DA9034_OVER2 (0x11)
+#define DA9034_OVER3 (0x12)
+#define DA9034_LDO643 (0x13)
+#define DA9034_LDO987 (0x14)
+#define DA9034_LDO1110 (0x15)
+#define DA9034_LDO1312 (0x16)
+#define DA9034_LDO1514 (0x17)
+#define DA9034_VCC1 (0x20)
+#define DA9034_ADTV1 (0x23)
+#define DA9034_ADTV2 (0x24)
+#define DA9034_AVRC (0x25)
+#define DA9034_CDTV1 (0x26)
+#define DA9034_CDTV2 (0x27)
+#define DA9034_CVRC (0x28)
+#define DA9034_SDTV1 (0x29)
+#define DA9034_SDTV2 (0x2a)
+#define DA9034_SVRC (0x2b)
+#define DA9034_MDTV1 (0x32)
+#define DA9034_MDTV2 (0x33)
+#define DA9034_MVRC (0x34)
+
+struct da903x_regulator_info {
+ struct regulator_desc desc;
+
+ int min_uV;
+ int max_uV;
+ int step_uV;
+ int vol_reg;
+ int vol_shift;
+ int vol_nbits;
+ int update_reg;
+ int update_bit;
+ int enable_reg;
+ int enable_bit;
+};
+
+static inline int check_range(struct da903x_regulator_info *info,
+ int min_uV, int max_uV)
+{
+ if (min_uV < info->min_uV || min_uV > info->max_uV)
+ return -EINVAL;
+
+ return 0;
+}
+
+/* DA9030/DA9034 common operations */
+static int da903x_set_ldo_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da903x_get_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ return info->min_uV + info->step_uV * val;
+}
+
+static int da903x_enable(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+ return da903x_set_bits(da9034_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int da903x_disable(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+
+ return da903x_clr_bits(da9034_dev, info->enable_reg,
+ 1 << info->enable_bit);
+}
+
+static int da903x_is_enabled(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t reg_val;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->enable_reg, &reg_val);
+ if (ret)
+ return ret;
+
+ return reg_val & (1 << info->enable_bit);
+}
+
+/* DA9030 specific operations */
+static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val |= DA9030_LDO_UNLOCK; /* have to set UNLOCK bits */
+ mask |= DA9030_LDO_UNLOCK_MASK;
+
+ /* write twice */
+ ret = da903x_update(da903x_dev, info->vol_reg, val, mask);
+ if (ret)
+ return ret;
+
+ return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_set_ldo14_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int thresh;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ thresh = (info->max_uV + info->min_uV) / 2;
+ if (min_uV < thresh) {
+ val = (thresh - min_uV + info->step_uV - 1) / info->step_uV;
+ val |= 0x4;
+ } else {
+ val = (min_uV - thresh + info->step_uV - 1) / info->step_uV;
+ }
+
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da903x_dev, info->vol_reg, val, mask);
+}
+
+static int da9030_get_ldo14_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da903x_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da903x_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ if (val & 0x4)
+ return info->min_uV + info->step_uV * (3 - (val & ~0x4));
+ else
+ return (info->max_uV + info->min_uV) / 2 +
+ info->step_uV * (val & ~0x4);
+}
+
+/* DA9034 specific operations */
+static int da9034_set_dvc_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ ret = da903x_update(da9034_dev, info->vol_reg, val, mask);
+ if (ret)
+ return ret;
+
+ ret = da903x_set_bits(da9034_dev, info->update_reg,
+ 1 << info->update_bit);
+ return ret;
+}
+
+static int da9034_set_ldo12_voltage(struct regulator_dev *rdev,
+ int min_uV, int max_uV)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+
+ if (check_range(info, min_uV, max_uV)) {
+ pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV);
+ return -EINVAL;
+ }
+
+ val = (min_uV - info->min_uV + info->step_uV - 1) / info->step_uV;
+ val = (val > 7 || val < 20) ? 8 : val - 12;
+ val <<= info->vol_shift;
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+
+ return da903x_update(da9034_dev, info->vol_reg, val, mask);
+}
+
+static int da9034_get_ldo12_voltage(struct regulator_dev *rdev)
+{
+ struct da903x_regulator_info *info = rdev_get_drvdata(rdev);
+ struct device *da9034_dev = rdev_get_dev(rdev)->parent;
+ uint8_t val, mask;
+ int ret;
+
+ ret = da903x_read(da9034_dev, info->vol_reg, &val);
+ if (ret)
+ return ret;
+
+ mask = ((1 << info->vol_nbits) - 1) << info->vol_shift;
+ val = (val & mask) >> info->vol_shift;
+
+ if (val >= 8)
+ return 2700000 + info->step_uV * (val - 8);
+
+ return info->min_uV + info->step_uV * val;
+}
+
+static struct regulator_ops da903x_regulator_ldo_ops = {
+ .set_voltage = da903x_set_ldo_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane DA9030 LDO14 */
+static struct regulator_ops da9030_regulator_ldo14_ops = {
+ .set_voltage = da9030_set_ldo14_voltage,
+ .get_voltage = da9030_get_ldo14_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the DA9030 LDO1 and LDO15 that have locks */
+static struct regulator_ops da9030_regulator_ldo1_15_ops = {
+ .set_voltage = da9030_set_ldo1_15_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+static struct regulator_ops da9034_regulator_dvc_ops = {
+ .set_voltage = da9034_set_dvc_voltage,
+ .get_voltage = da903x_get_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+/* NOTE: this is dedicated for the insane LDO12 */
+static struct regulator_ops da9034_regulator_ldo12_ops = {
+ .set_voltage = da9034_set_ldo12_voltage,
+ .get_voltage = da9034_get_ldo12_voltage,
+ .enable = da903x_enable,
+ .disable = da903x_disable,
+ .is_enabled = da903x_is_enabled,
+};
+
+#define DA903x_LDO(_pmic, _id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = "LDO" #_id, \
+ .ops = &da903x_regulator_ldo_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _pmic##_ID_LDO##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = _pmic##_##vreg, \
+ .vol_shift = (shift), \
+ .vol_nbits = (nbits), \
+ .enable_reg = _pmic##_##ereg, \
+ .enable_bit = (ebit), \
+}
+
+#define DA9034_DVC(_id, min, max, step, vreg, nbits, ureg, ubit, ereg, ebit) \
+{ \
+ .desc = { \
+ .name = #_id, \
+ .ops = &da9034_regulator_dvc_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = DA9034_ID_##_id, \
+ .owner = THIS_MODULE, \
+ }, \
+ .min_uV = (min) * 1000, \
+ .max_uV = (max) * 1000, \
+ .step_uV = (step) * 1000, \
+ .vol_reg = DA9034_##vreg, \
+ .vol_shift = (0), \
+ .vol_nbits = (nbits), \
+ .update_reg = DA9034_##ureg, \
+ .update_bit = (ubit), \
+ .enable_reg = DA9034_##ereg, \
+ .enable_bit = (ebit), \
+}
+
+#define DA9034_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ DA903x_LDO(DA9034, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+#define DA9030_LDO(_id, min, max, step, vreg, shift, nbits, ereg, ebit) \
+ DA903x_LDO(DA9030, _id, min, max, step, vreg, shift, nbits, ereg, ebit)
+
+static struct da903x_regulator_info da903x_regulator_info[] = {
+ /* DA9030 */
+ DA9030_LDO( 1, 1200, 3200, 100, LDO1, 0, 5, RCTL12, 1),
+ DA9030_LDO( 2, 1800, 3200, 100, LDO23, 0, 4, RCTL12, 2),
+ DA9030_LDO( 3, 1800, 3200, 100, LDO23, 4, 4, RCTL12, 3),
+ DA9030_LDO( 4, 1800, 3200, 100, LDO45, 0, 4, RCTL12, 4),
+ DA9030_LDO( 5, 1800, 3200, 100, LDO45, 4, 4, RCTL12, 5),
+ DA9030_LDO( 6, 1800, 3200, 100, LDO6, 0, 4, RCTL12, 6),
+ DA9030_LDO( 7, 1800, 3200, 100, LDO78, 0, 4, RCTL12, 7),
+ DA9030_LDO( 8, 1800, 3200, 100, LDO78, 4, 4, RCTL22, 0),
+ DA9030_LDO( 9, 1800, 3200, 100, LDO912, 0, 4, RCTL22, 1),
+ DA9030_LDO(10, 1800, 3200, 100, LDO1011, 0, 4, RCTL22, 2),
+ DA9030_LDO(11, 1800, 3200, 100, LDO1011, 4, 4, RCTL22, 3),
+ DA9030_LDO(12, 1800, 3200, 100, LDO912, 4, 4, RCTL22, 4),
+ DA9030_LDO(14, 2760, 2940, 30, LDO1416, 0, 3, RCTL11, 4),
+ DA9030_LDO(15, 1100, 2650, 50, LDO15, 0, 5, RCTL11, 5),
+ DA9030_LDO(16, 1100, 2650, 50, LDO1416, 3, 5, RCTL11, 6),
+ DA9030_LDO(17, 1800, 3200, 100, LDO17, 0, 4, RCTL11, 7),
+ DA9030_LDO(18, 1800, 3200, 100, LDO1819, 0, 4, RCTL21, 2),
+ DA9030_LDO(19, 1800, 3200, 100, LDO1819, 4, 4, RCTL21, 1),
+ DA9030_LDO(13, 2100, 2100, 0, INVAL, 0, 0, RCTL11, 3), /* fixed @2.1V */
+
+ /* DA9034 */
+ DA9034_DVC(BUCK1, 725, 1500, 25, ADTV1, 5, VCC1, 0, OVER1, 0),
+ DA9034_DVC(BUCK2, 725, 1500, 25, CDTV1, 5, VCC1, 2, OVER1, 1),
+ DA9034_DVC(LDO2, 725, 1500, 25, SDTV1, 5, VCC1, 4, OVER1, 2),
+ DA9034_DVC(LDO1, 1700, 2075, 25, MDTV1, 4, VCC1, 6, OVER3, 4),
+
+ DA9034_LDO( 3, 1800, 3300, 100, LDO643, 0, 4, OVER3, 5),
+ DA9034_LDO( 4, 1800, 2900,1100, LDO643, 4, 1, OVER3, 6),
+ DA9034_LDO( 6, 2500, 2850, 50, LDO643, 5, 3, OVER2, 0),
+ DA9034_LDO( 7, 2700, 3050, 50, LDO987, 0, 3, OVER2, 1),
+ DA9034_LDO( 8, 2700, 2850, 50, LDO987, 3, 2, OVER2, 2),
+ DA9034_LDO( 9, 2700, 3050, 50, LDO987, 5, 3, OVER2, 3),
+ DA9034_LDO(10, 2700, 3050, 50, LDO1110, 0, 3, OVER2, 4),
+ DA9034_LDO(11, 1800, 3300, 100, LDO1110, 4, 4, OVER2, 5),
+ DA9034_LDO(12, 1700, 3050, 50, LDO1312, 0, 4, OVER3, 6),
+ DA9034_LDO(13, 1800, 3300, 100, LDO1312, 4, 4, OVER2, 7),
+ DA9034_LDO(14, 1800, 3300, 100, LDO1514, 0, 4, OVER3, 0),
+ DA9034_LDO(15, 1800, 3300, 100, LDO1514, 4, 4, OVER3, 1),
+ DA9034_LDO(5, 3100, 3100, 0, INVAL, 0, 0, OVER3, 7), /* fixed @3.1V */
+};
+
+static inline struct da903x_regulator_info *find_regulator_info(int id)
+{
+ struct da903x_regulator_info *ri;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(da903x_regulator_info); i++) {
+ ri = &da903x_regulator_info[i];
+ if (ri->desc.id == id)
+ return ri;
+ }
+ return NULL;
+}
+
+static int __devinit da903x_regulator_probe(struct platform_device *pdev)
+{
+ struct da903x_regulator_info *ri = NULL;
+ struct regulator_dev *rdev;
+
+ ri = find_regulator_info(pdev->id);
+ if (ri == NULL) {
+ dev_err(&pdev->dev, "invalid regulator ID specified\n");
+ return -EINVAL;
+ }
+
+ /* Workaround for the weird LDO12 voltage setting */
+ if (ri->desc.id == DA9034_ID_LDO12)
+ ri->desc.ops = &da9034_regulator_ldo12_ops;
+
+ if (ri->desc.id == DA9030_ID_LDO14)
+ ri->desc.ops = &da9030_regulator_ldo14_ops;
+
+ if (ri->desc.id == DA9030_ID_LDO1 || ri->desc.id == DA9030_ID_LDO15)
+ ri->desc.ops = &da9030_regulator_ldo1_15_ops;
+
+ rdev = regulator_register(&ri->desc, pdev->dev.parent, ri);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register regulator %s\n",
+ ri->desc.name);
+ return PTR_ERR(rdev);
+ }
+
+ platform_set_drvdata(pdev, rdev);
+ return 0;
+}
+
+static int __devexit da903x_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+ return 0;
+}
+
+static struct platform_driver da903x_regulator_driver = {
+ .driver = {
+ .name = "da903x-regulator",
+ .owner = THIS_MODULE,
+ },
+ .probe = da903x_regulator_probe,
+ .remove = da903x_regulator_remove,
+};
+
+static int __init da903x_regulator_init(void)
+{
+ return platform_driver_register(&da903x_regulator_driver);
+}
+module_init(da903x_regulator_init);
+
+static void __exit da903x_regulator_exit(void)
+{
+ platform_driver_unregister(&da903x_regulator_driver);
+}
+module_exit(da903x_regulator_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"
+ "Mike Rapoport <mike@compulab.co.il>");
+MODULE_DESCRIPTION("Regulator Driver for Dialog Semiconductor DA903X PMIC");
+MODULE_ALIAS("platform:da903x-regulator");
diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c
new file mode 100644
index 00000000000..1f44b17e23b
--- /dev/null
+++ b/drivers/regulator/wm8350-regulator.c
@@ -0,0 +1,1431 @@
+/*
+ * wm8350.c -- Voltage and current regulation for the Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Liam Girdwood
+ * linux@wolfsonmicro.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/mfd/wm8350/core.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+
+/* Microamps */
+static const int isink_cur[] = {
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 10,
+ 11,
+ 14,
+ 16,
+ 19,
+ 23,
+ 27,
+ 32,
+ 39,
+ 46,
+ 54,
+ 65,
+ 77,
+ 92,
+ 109,
+ 130,
+ 154,
+ 183,
+ 218,
+ 259,
+ 308,
+ 367,
+ 436,
+ 518,
+ 616,
+ 733,
+ 872,
+ 1037,
+ 1233,
+ 1466,
+ 1744,
+ 2073,
+ 2466,
+ 2933,
+ 3487,
+ 4147,
+ 4932,
+ 5865,
+ 6975,
+ 8294,
+ 9864,
+ 11730,
+ 13949,
+ 16589,
+ 19728,
+ 23460,
+ 27899,
+ 33178,
+ 39455,
+ 46920,
+ 55798,
+ 66355,
+ 78910,
+ 93840,
+ 111596,
+ 132710,
+ 157820,
+ 187681,
+ 223191
+};
+
+static int get_isink_val(int min_uA, int max_uA, u16 *setting)
+{
+ int i;
+
+ for (i = ARRAY_SIZE(isink_cur) - 1; i >= 0; i--) {
+ if (min_uA <= isink_cur[i] && max_uA >= isink_cur[i]) {
+ *setting = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static inline int wm8350_ldo_val_to_mvolts(unsigned int val)
+{
+ if (val < 16)
+ return (val * 50) + 900;
+ else
+ return ((val - 16) * 100) + 1800;
+
+}
+
+static inline unsigned int wm8350_ldo_mvolts_to_val(int mV)
+{
+ if (mV < 1800)
+ return (mV - 900) / 50;
+ else
+ return ((mV - 1800) / 100) + 16;
+}
+
+static inline int wm8350_dcdc_val_to_mvolts(unsigned int val)
+{
+ return (val * 25) + 850;
+}
+
+static inline unsigned int wm8350_dcdc_mvolts_to_val(int mV)
+{
+ return (mV - 850) / 25;
+}
+
+static int wm8350_isink_set_current(struct regulator_dev *rdev, int min_uA,
+ int max_uA)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+ u16 val, setting;
+ int ret;
+
+ ret = get_isink_val(min_uA, max_uA, &setting);
+ if (ret != 0)
+ return ret;
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ ~WM8350_CS1_ISEL_MASK;
+ wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_A,
+ val | setting);
+ break;
+ case WM8350_ISINK_B:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ ~WM8350_CS1_ISEL_MASK;
+ wm8350_reg_write(wm8350, WM8350_CURRENT_SINK_DRIVER_B,
+ val | setting);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_isink_get_current(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+ u16 val;
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ WM8350_CS1_ISEL_MASK;
+ break;
+ case WM8350_ISINK_B:
+ val = wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ WM8350_CS1_ISEL_MASK;
+ break;
+ default:
+ return 0;
+ }
+
+ return (isink_cur[val] + 50) / 100;
+}
+
+/* turn on ISINK followed by DCDC */
+static int wm8350_isink_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ switch (wm8350->pmic.isink_A_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS1_ENA);
+ wm8350_set_bits(wm8350, WM8350_CSA_FLASH_CONTROL,
+ WM8350_CS1_DRIVE);
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_A_dcdc -
+ WM8350_DCDC_1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case WM8350_ISINK_B:
+ switch (wm8350->pmic.isink_B_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_set_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS2_ENA);
+ wm8350_set_bits(wm8350, WM8350_CSB_FLASH_CONTROL,
+ WM8350_CS2_DRIVE);
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_B_dcdc -
+ WM8350_DCDC_1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_isink_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ switch (wm8350->pmic.isink_A_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_A_dcdc -
+ WM8350_DCDC_1));
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS1_ENA);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case WM8350_ISINK_B:
+ switch (wm8350->pmic.isink_B_dcdc) {
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED,
+ 1 << (wm8350->pmic.isink_B_dcdc -
+ WM8350_DCDC_1));
+ wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_7,
+ WM8350_CS2_ENA);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_isink_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int isink = rdev_get_id(rdev);
+
+ switch (isink) {
+ case WM8350_ISINK_A:
+ return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_A) &
+ 0x8000;
+ case WM8350_ISINK_B:
+ return wm8350_reg_read(wm8350, WM8350_CURRENT_SINK_DRIVER_B) &
+ 0x8000;
+ }
+ return -EINVAL;
+}
+
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+ u16 trigger, u16 duration, u16 on_ramp, u16 off_ramp,
+ u16 drive)
+{
+ switch (isink) {
+ case WM8350_ISINK_A:
+ wm8350_reg_write(wm8350, WM8350_CSA_FLASH_CONTROL,
+ (mode ? WM8350_CS1_FLASH_MODE : 0) |
+ (trigger ? WM8350_CS1_TRIGSRC : 0) |
+ duration | on_ramp | off_ramp | drive);
+ break;
+ case WM8350_ISINK_B:
+ wm8350_reg_write(wm8350, WM8350_CSB_FLASH_CONTROL,
+ (mode ? WM8350_CS2_FLASH_MODE : 0) |
+ (trigger ? WM8350_CS2_TRIGSRC : 0) |
+ duration | on_ramp | off_ramp | drive);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_isink_set_flash);
+
+static int wm8350_dcdc_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, dcdc = rdev_get_id(rdev), mV,
+ min_mV = min_uV / 1000, max_mV = max_uV / 1000;
+ u16 val;
+
+ if (min_mV < 850 || min_mV > 4025)
+ return -EINVAL;
+ if (max_mV < 850 || max_mV > 4025)
+ return -EINVAL;
+
+ /* step size is 25mV */
+ mV = (min_mV - 826) / 25;
+ if (wm8350_dcdc_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_dcdc_val_to_mvolts(mV) < min_mV);
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_CONTROL;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_CONTROL;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_CONTROL;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_CONTROL;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val | mV);
+ return 0;
+}
+
+static int wm8350_dcdc_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_CONTROL;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_CONTROL;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_CONTROL;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_CONTROL;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & WM8350_DC1_VSEL_MASK;
+ return wm8350_dcdc_val_to_mvolts(val) * 1000;
+}
+
+static int wm8350_dcdc_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, mV = uV / 1000, dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, dcdc, mV);
+
+ if (mV && (mV < 850 || mV > 4025)) {
+ dev_err(wm8350->dev,
+ "DCDC%d suspend voltage %d mV out of range\n",
+ dcdc, mV);
+ return -EINVAL;
+ }
+ if (mV == 0)
+ mV = 850;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ volt_reg = WM8350_DCDC1_LOW_POWER;
+ break;
+ case WM8350_DCDC_3:
+ volt_reg = WM8350_DCDC3_LOW_POWER;
+ break;
+ case WM8350_DCDC_4:
+ volt_reg = WM8350_DCDC4_LOW_POWER;
+ break;
+ case WM8350_DCDC_6:
+ volt_reg = WM8350_DCDC6_LOW_POWER;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ /* all DCDCs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_DC1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg,
+ val | wm8350_dcdc_mvolts_to_val(mV));
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+ wm8350->pmic.dcdc1_hib_mode);
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+ wm8350->pmic.dcdc3_hib_mode);
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+ wm8350->pmic.dcdc4_hib_mode);
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER)
+ & ~WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+ wm8350->pmic.dcdc6_hib_mode);
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+ wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC1_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+ wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC3_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+ wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC4_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+ wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC6_LOW_POWER,
+ WM8350_DCDC_HIB_MODE_DIS);
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ WM8350_DC2_HIB_MODE_ACTIVE);
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ WM8350_DC5_HIB_MODE_ACTIVE);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_dcdc25_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ WM8350_DC2_HIB_MODE_DISABLE);
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~WM8350_DC2_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ WM8350_DC2_HIB_MODE_DISABLE);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int wm8350_dcdc_set_suspend_mode(struct regulator_dev *rdev,
+ unsigned int mode)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 *hib_mode;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ hib_mode = &wm8350->pmic.dcdc1_hib_mode;
+ break;
+ case WM8350_DCDC_3:
+ hib_mode = &wm8350->pmic.dcdc3_hib_mode;
+ break;
+ case WM8350_DCDC_4:
+ hib_mode = &wm8350->pmic.dcdc4_hib_mode;
+ break;
+ case WM8350_DCDC_6:
+ hib_mode = &wm8350->pmic.dcdc6_hib_mode;
+ break;
+ case WM8350_DCDC_2:
+ case WM8350_DCDC_5:
+ default:
+ return -EINVAL;
+ }
+
+ switch (mode) {
+ case REGULATOR_MODE_NORMAL:
+ *hib_mode = WM8350_DCDC_HIB_MODE_IMAGE;
+ break;
+ case REGULATOR_MODE_IDLE:
+ *hib_mode = WM8350_DCDC_HIB_MODE_STANDBY;
+ break;
+ case REGULATOR_MODE_STANDBY:
+ *hib_mode = WM8350_DCDC_HIB_MODE_LDO_IM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_voltage(struct regulator_dev *rdev, int uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, mV = uV / 1000, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mV %d\n", __func__, ldo, mV);
+
+ if (mV < 900 || mV > 3300) {
+ dev_err(wm8350->dev, "LDO%d voltage %d mV out of range\n",
+ ldo, mV);
+ return -EINVAL;
+ }
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg,
+ val | wm8350_ldo_mvolts_to_val(mV));
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val);
+ return 0;
+}
+
+static int wm8350_ldo_set_suspend_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_LOW_POWER;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_LOW_POWER;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_LOW_POWER;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_LOW_POWER;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_HIB_MODE_MASK;
+ wm8350_reg_write(wm8350, volt_reg, WM8350_LDO1_HIB_MODE_DIS);
+ return 0;
+}
+
+static int wm8350_ldo_set_voltage(struct regulator_dev *rdev, int min_uV,
+ int max_uV)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev), mV, min_mV = min_uV / 1000,
+ max_mV = max_uV / 1000;
+ u16 val;
+
+ if (min_mV < 900 || min_mV > 3300)
+ return -EINVAL;
+ if (max_mV < 900 || max_mV > 3300)
+ return -EINVAL;
+
+ if (min_mV < 1800) {
+ /* step size is 50mV < 1800mV */
+ mV = (min_mV - 851) / 50;
+ if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+ } else {
+ /* step size is 100mV > 1800mV */
+ mV = ((min_mV - 1701) / 100) + 16;
+ if (wm8350_ldo_val_to_mvolts(mV) > max_mV)
+ return -EINVAL;
+ BUG_ON(wm8350_ldo_val_to_mvolts(mV) < min_mV);
+ }
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_CONTROL;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_CONTROL;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_CONTROL;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_CONTROL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & ~WM8350_LDO1_VSEL_MASK;
+ wm8350_reg_write(wm8350, volt_reg, val | mV);
+ return 0;
+}
+
+static int wm8350_ldo_get_voltage(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int volt_reg, ldo = rdev_get_id(rdev);
+ u16 val;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ volt_reg = WM8350_LDO1_CONTROL;
+ break;
+ case WM8350_LDO_2:
+ volt_reg = WM8350_LDO2_CONTROL;
+ break;
+ case WM8350_LDO_3:
+ volt_reg = WM8350_LDO3_CONTROL;
+ break;
+ case WM8350_LDO_4:
+ volt_reg = WM8350_LDO4_CONTROL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* all LDOs have same mV bits */
+ val = wm8350_reg_read(wm8350, volt_reg) & WM8350_LDO1_VSEL_MASK;
+ return wm8350_ldo_val_to_mvolts(val) * 1000;
+}
+
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+ u16 stop, u16 fault)
+{
+ int slot_reg;
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+ __func__, dcdc, start, stop);
+
+ /* slot valid ? */
+ if (start > 15 || stop > 15)
+ return -EINVAL;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ slot_reg = WM8350_DCDC1_TIMEOUTS;
+ break;
+ case WM8350_DCDC_2:
+ slot_reg = WM8350_DCDC2_TIMEOUTS;
+ break;
+ case WM8350_DCDC_3:
+ slot_reg = WM8350_DCDC3_TIMEOUTS;
+ break;
+ case WM8350_DCDC_4:
+ slot_reg = WM8350_DCDC4_TIMEOUTS;
+ break;
+ case WM8350_DCDC_5:
+ slot_reg = WM8350_DCDC5_TIMEOUTS;
+ break;
+ case WM8350_DCDC_6:
+ slot_reg = WM8350_DCDC6_TIMEOUTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = wm8350_reg_read(wm8350, slot_reg) &
+ ~(WM8350_DC1_ENSLOT_MASK | WM8350_DC1_SDSLOT_MASK |
+ WM8350_DC1_ERRACT_MASK);
+ wm8350_reg_write(wm8350, slot_reg,
+ val | (start << WM8350_DC1_ENSLOT_SHIFT) |
+ (stop << WM8350_DC1_SDSLOT_SHIFT) |
+ (fault << WM8350_DC1_ERRACT_SHIFT));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc_set_slot);
+
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop)
+{
+ int slot_reg;
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d start %d stop %d\n",
+ __func__, ldo, start, stop);
+
+ /* slot valid ? */
+ if (start > 15 || stop > 15)
+ return -EINVAL;
+
+ switch (ldo) {
+ case WM8350_LDO_1:
+ slot_reg = WM8350_LDO1_TIMEOUTS;
+ break;
+ case WM8350_LDO_2:
+ slot_reg = WM8350_LDO2_TIMEOUTS;
+ break;
+ case WM8350_LDO_3:
+ slot_reg = WM8350_LDO3_TIMEOUTS;
+ break;
+ case WM8350_LDO_4:
+ slot_reg = WM8350_LDO4_TIMEOUTS;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = wm8350_reg_read(wm8350, slot_reg) & ~WM8350_LDO1_SDSLOT_MASK;
+ wm8350_reg_write(wm8350, slot_reg, val | ((start << 10) | (stop << 6)));
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_ldo_set_slot);
+
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+ u16 ilim, u16 ramp, u16 feedback)
+{
+ u16 val;
+
+ dev_dbg(wm8350->dev, "%s %d mode: %s %s\n", __func__, dcdc,
+ mode ? "normal" : "boost", ilim ? "low" : "normal");
+
+ switch (dcdc) {
+ case WM8350_DCDC_2:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC2_CONTROL)
+ & ~(WM8350_DC2_MODE_MASK | WM8350_DC2_ILIM_MASK |
+ WM8350_DC2_RMP_MASK | WM8350_DC2_FBSRC_MASK);
+ wm8350_reg_write(wm8350, WM8350_DCDC2_CONTROL, val |
+ (mode << WM8350_DC2_MODE_SHIFT) |
+ (ilim << WM8350_DC2_ILIM_SHIFT) |
+ (ramp << WM8350_DC2_RMP_SHIFT) |
+ (feedback << WM8350_DC2_FBSRC_SHIFT));
+ break;
+ case WM8350_DCDC_5:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC5_CONTROL)
+ & ~(WM8350_DC5_MODE_MASK | WM8350_DC5_ILIM_MASK |
+ WM8350_DC5_RMP_MASK | WM8350_DC5_FBSRC_MASK);
+ wm8350_reg_write(wm8350, WM8350_DCDC5_CONTROL, val |
+ (mode << WM8350_DC5_MODE_SHIFT) |
+ (ilim << WM8350_DC5_ILIM_SHIFT) |
+ (ramp << WM8350_DC5_RMP_SHIFT) |
+ (feedback << WM8350_DC5_FBSRC_SHIFT));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(wm8350_dcdc25_set_mode);
+
+static int wm8350_dcdc_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int wm8350_dcdc_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+
+ return 0;
+}
+
+static int wm8350_ldo_enable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev);
+ u16 shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ wm8350_set_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int wm8350_ldo_disable(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev);
+ u16 shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ wm8350_clear_bits(wm8350, WM8350_DCDC_LDO_REQUESTED, 1 << shift);
+ return 0;
+}
+
+static int force_continuous_enable(struct wm8350 *wm8350, int dcdc, int enable)
+{
+ int reg = 0, ret;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ reg = WM8350_DCDC1_FORCE_PWM;
+ break;
+ case WM8350_DCDC_3:
+ reg = WM8350_DCDC3_FORCE_PWM;
+ break;
+ case WM8350_DCDC_4:
+ reg = WM8350_DCDC4_FORCE_PWM;
+ break;
+ case WM8350_DCDC_6:
+ reg = WM8350_DCDC6_FORCE_PWM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (enable)
+ ret = wm8350_set_bits(wm8350, reg,
+ WM8350_DCDC1_FORCE_PWM_ENA);
+ else
+ ret = wm8350_clear_bits(wm8350, reg,
+ WM8350_DCDC1_FORCE_PWM_ENA);
+ return ret;
+}
+
+static int wm8350_dcdc_set_mode(struct regulator_dev *rdev, unsigned int mode)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 val;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+ return -EINVAL;
+
+ val = 1 << (dcdc - WM8350_DCDC_1);
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ /* force continuous mode */
+ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ force_continuous_enable(wm8350, dcdc, 1);
+ break;
+ case REGULATOR_MODE_NORMAL:
+ /* active / pulse skipping */
+ wm8350_set_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ force_continuous_enable(wm8350, dcdc, 0);
+ break;
+ case REGULATOR_MODE_IDLE:
+ /* standby mode */
+ force_continuous_enable(wm8350, dcdc, 0);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ wm8350_clear_bits(wm8350, WM8350_DCDC_ACTIVE_OPTIONS, val);
+ break;
+ case REGULATOR_MODE_STANDBY:
+ /* LDO mode */
+ force_continuous_enable(wm8350, dcdc, 0);
+ wm8350_set_bits(wm8350, WM8350_DCDC_SLEEP_OPTIONS, val);
+ break;
+ }
+
+ return 0;
+}
+
+static unsigned int wm8350_dcdc_get_mode(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev);
+ u16 mask, sleep, active, force;
+ int mode = REGULATOR_MODE_NORMAL;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ if (dcdc == WM8350_DCDC_2 || dcdc == WM8350_DCDC_5)
+ return -EINVAL;
+
+ mask = 1 << (dcdc - WM8350_DCDC_1);
+ active = wm8350_reg_read(wm8350, WM8350_DCDC_ACTIVE_OPTIONS) & mask;
+ sleep = wm8350_reg_read(wm8350, WM8350_DCDC_SLEEP_OPTIONS) & mask;
+ force = wm8350_reg_read(wm8350, WM8350_DCDC1_FORCE_PWM)
+ & WM8350_DCDC1_FORCE_PWM_ENA;
+ dev_dbg(wm8350->dev, "mask %x active %x sleep %x force %x",
+ mask, active, sleep, force);
+
+ if (active && !sleep) {
+ if (force)
+ mode = REGULATOR_MODE_FAST;
+ else
+ mode = REGULATOR_MODE_NORMAL;
+ } else if (!active && !sleep)
+ mode = REGULATOR_MODE_IDLE;
+ else if (!sleep)
+ mode = REGULATOR_MODE_STANDBY;
+
+ return mode;
+}
+
+static unsigned int wm8350_ldo_get_mode(struct regulator_dev *rdev)
+{
+ return REGULATOR_MODE_NORMAL;
+}
+
+struct wm8350_dcdc_efficiency {
+ int uA_load_min;
+ int uA_load_max;
+ unsigned int mode;
+};
+
+static const struct wm8350_dcdc_efficiency dcdc1_6_efficiency[] = {
+ {0, 10000, REGULATOR_MODE_STANDBY}, /* 0 - 10mA - LDO */
+ {10000, 100000, REGULATOR_MODE_IDLE}, /* 10mA - 100mA - Standby */
+ {100000, 1000000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+ {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static const struct wm8350_dcdc_efficiency dcdc3_4_efficiency[] = {
+ {0, 10000, REGULATOR_MODE_STANDBY}, /* 0 - 10mA - LDO */
+ {10000, 100000, REGULATOR_MODE_IDLE}, /* 10mA - 100mA - Standby */
+ {100000, 800000, REGULATOR_MODE_NORMAL}, /* > 100mA - Active */
+ {-1, -1, REGULATOR_MODE_NORMAL},
+};
+
+static unsigned int get_mode(int uA, const struct wm8350_dcdc_efficiency *eff)
+{
+ int i = 0;
+
+ while (eff[i].uA_load_min != -1) {
+ if (uA >= eff[i].uA_load_min && uA <= eff[i].uA_load_max)
+ return eff[i].mode;
+ }
+ return REGULATOR_MODE_NORMAL;
+}
+
+/* Query the regulator for it's most efficient mode @ uV,uA
+ * WM8350 regulator efficiency is pretty similar over
+ * different input and output uV.
+ */
+static unsigned int wm8350_dcdc_get_optimum_mode(struct regulator_dev *rdev,
+ int input_uV, int output_uV,
+ int output_uA)
+{
+ int dcdc = rdev_get_id(rdev), mode;
+
+ switch (dcdc) {
+ case WM8350_DCDC_1:
+ case WM8350_DCDC_6:
+ mode = get_mode(output_uA, dcdc1_6_efficiency);
+ break;
+ case WM8350_DCDC_3:
+ case WM8350_DCDC_4:
+ mode = get_mode(output_uA, dcdc3_4_efficiency);
+ break;
+ default:
+ mode = REGULATOR_MODE_NORMAL;
+ break;
+ }
+ return mode;
+}
+
+static int wm8350_dcdc_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int dcdc = rdev_get_id(rdev), shift;
+
+ if (dcdc < WM8350_DCDC_1 || dcdc > WM8350_DCDC_6)
+ return -EINVAL;
+
+ shift = dcdc - WM8350_DCDC_1;
+ return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+ & (1 << shift);
+}
+
+static int wm8350_ldo_is_enabled(struct regulator_dev *rdev)
+{
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+ int ldo = rdev_get_id(rdev), shift;
+
+ if (ldo < WM8350_LDO_1 || ldo > WM8350_LDO_4)
+ return -EINVAL;
+
+ shift = (ldo - WM8350_LDO_1) + 8;
+ return wm8350_reg_read(wm8350, WM8350_DCDC_LDO_REQUESTED)
+ & (1 << shift);
+}
+
+static struct regulator_ops wm8350_dcdc_ops = {
+ .set_voltage = wm8350_dcdc_set_voltage,
+ .get_voltage = wm8350_dcdc_get_voltage,
+ .enable = wm8350_dcdc_enable,
+ .disable = wm8350_dcdc_disable,
+ .get_mode = wm8350_dcdc_get_mode,
+ .set_mode = wm8350_dcdc_set_mode,
+ .get_optimum_mode = wm8350_dcdc_get_optimum_mode,
+ .is_enabled = wm8350_dcdc_is_enabled,
+ .set_suspend_voltage = wm8350_dcdc_set_suspend_voltage,
+ .set_suspend_enable = wm8350_dcdc_set_suspend_enable,
+ .set_suspend_disable = wm8350_dcdc_set_suspend_disable,
+ .set_suspend_mode = wm8350_dcdc_set_suspend_mode,
+};
+
+static struct regulator_ops wm8350_dcdc2_5_ops = {
+ .enable = wm8350_dcdc_enable,
+ .disable = wm8350_dcdc_disable,
+ .is_enabled = wm8350_dcdc_is_enabled,
+ .set_suspend_enable = wm8350_dcdc25_set_suspend_enable,
+ .set_suspend_disable = wm8350_dcdc25_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_ldo_ops = {
+ .set_voltage = wm8350_ldo_set_voltage,
+ .get_voltage = wm8350_ldo_get_voltage,
+ .enable = wm8350_ldo_enable,
+ .disable = wm8350_ldo_disable,
+ .is_enabled = wm8350_ldo_is_enabled,
+ .get_mode = wm8350_ldo_get_mode,
+ .set_suspend_voltage = wm8350_ldo_set_suspend_voltage,
+ .set_suspend_enable = wm8350_ldo_set_suspend_enable,
+ .set_suspend_disable = wm8350_ldo_set_suspend_disable,
+};
+
+static struct regulator_ops wm8350_isink_ops = {
+ .set_current_limit = wm8350_isink_set_current,
+ .get_current_limit = wm8350_isink_get_current,
+ .enable = wm8350_isink_enable,
+ .disable = wm8350_isink_disable,
+ .is_enabled = wm8350_isink_is_enabled,
+};
+
+static struct regulator_desc wm8350_reg[NUM_WM8350_REGULATORS] = {
+ {
+ .name = "DCDC1",
+ .id = WM8350_DCDC_1,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC2",
+ .id = WM8350_DCDC_2,
+ .ops = &wm8350_dcdc2_5_ops,
+ .irq = WM8350_IRQ_UV_DC2,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC3",
+ .id = WM8350_DCDC_3,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC3,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC4",
+ .id = WM8350_DCDC_4,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC4,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC5",
+ .id = WM8350_DCDC_5,
+ .ops = &wm8350_dcdc2_5_ops,
+ .irq = WM8350_IRQ_UV_DC5,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC6",
+ .id = WM8350_DCDC_6,
+ .ops = &wm8350_dcdc_ops,
+ .irq = WM8350_IRQ_UV_DC6,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO1",
+ .id = WM8350_LDO_1,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO1,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = WM8350_LDO_2,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO2,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = WM8350_LDO_3,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO3,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = WM8350_LDO_4,
+ .ops = &wm8350_ldo_ops,
+ .irq = WM8350_IRQ_UV_LDO4,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ISINKA",
+ .id = WM8350_ISINK_A,
+ .ops = &wm8350_isink_ops,
+ .irq = WM8350_IRQ_CS1,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "ISINKB",
+ .id = WM8350_ISINK_B,
+ .ops = &wm8350_isink_ops,
+ .irq = WM8350_IRQ_CS2,
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ },
+};
+
+static void pmic_uv_handler(struct wm8350 *wm8350, int irq, void *data)
+{
+ struct regulator_dev *rdev = (struct regulator_dev *)data;
+
+ if (irq == WM8350_IRQ_CS1 || irq == WM8350_IRQ_CS2)
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_REGULATION_OUT,
+ wm8350);
+ else
+ regulator_notifier_call_chain(rdev,
+ REGULATOR_EVENT_UNDER_VOLTAGE,
+ wm8350);
+}
+
+static int wm8350_regulator_probe(struct platform_device *pdev)
+{
+ struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);
+ struct regulator_dev *rdev;
+ int ret;
+ u16 val;
+
+ if (pdev->id < WM8350_DCDC_1 || pdev->id > WM8350_ISINK_B)
+ return -ENODEV;
+
+ /* do any regulatior specific init */
+ switch (pdev->id) {
+ case WM8350_DCDC_1:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC1_LOW_POWER);
+ wm8350->pmic.dcdc1_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_3:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC3_LOW_POWER);
+ wm8350->pmic.dcdc3_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_4:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC4_LOW_POWER);
+ wm8350->pmic.dcdc4_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ case WM8350_DCDC_6:
+ val = wm8350_reg_read(wm8350, WM8350_DCDC6_LOW_POWER);
+ wm8350->pmic.dcdc6_hib_mode = val & WM8350_DCDC_HIB_MODE_MASK;
+ break;
+ }
+
+
+ /* register regulator */
+ rdev = regulator_register(&wm8350_reg[pdev->id], &pdev->dev,
+ dev_get_drvdata(&pdev->dev));
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ wm8350_reg[pdev->id].name);
+ return PTR_ERR(rdev);
+ }
+
+ /* register regulator IRQ */
+ ret = wm8350_register_irq(wm8350, wm8350_reg[pdev->id].irq,
+ pmic_uv_handler, rdev);
+ if (ret < 0) {
+ regulator_unregister(rdev);
+ dev_err(&pdev->dev, "failed to register regulator %s IRQ\n",
+ wm8350_reg[pdev->id].name);
+ return ret;
+ }
+
+ wm8350_unmask_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+ return 0;
+}
+
+static int wm8350_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+ struct wm8350 *wm8350 = rdev_get_drvdata(rdev);
+
+ wm8350_mask_irq(wm8350, wm8350_reg[pdev->id].irq);
+ wm8350_free_irq(wm8350, wm8350_reg[pdev->id].irq);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+ struct regulator_init_data *initdata)
+{
+ struct platform_device *pdev;
+ int ret;
+
+ if (wm8350->pmic.pdev[reg])
+ return -EBUSY;
+
+ pdev = platform_device_alloc("wm8350-regulator", reg);
+ if (!pdev)
+ return -ENOMEM;
+
+ wm8350->pmic.pdev[reg] = pdev;
+
+ initdata->driver_data = wm8350;
+
+ pdev->dev.platform_data = initdata;
+ pdev->dev.parent = wm8350->dev;
+ platform_set_drvdata(pdev, wm8350);
+
+ ret = platform_device_add(pdev);
+
+ if (ret != 0) {
+ dev_err(wm8350->dev, "Failed to register regulator %d: %d\n",
+ reg, ret);
+ platform_device_del(pdev);
+ wm8350->pmic.pdev[reg] = NULL;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(wm8350_register_regulator);
+
+static struct platform_driver wm8350_regulator_driver = {
+ .probe = wm8350_regulator_probe,
+ .remove = wm8350_regulator_remove,
+ .driver = {
+ .name = "wm8350-regulator",
+ },
+};
+
+static int __init wm8350_regulator_init(void)
+{
+ return platform_driver_register(&wm8350_regulator_driver);
+}
+subsys_initcall(wm8350_regulator_init);
+
+static void __exit wm8350_regulator_exit(void)
+{
+ platform_driver_unregister(&wm8350_regulator_driver);
+}
+module_exit(wm8350_regulator_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_DESCRIPTION("WM8350 voltage and current regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/wm8400-regulator.c b/drivers/regulator/wm8400-regulator.c
new file mode 100644
index 00000000000..48b372e038a
--- /dev/null
+++ b/drivers/regulator/wm8400-regulator.c
@@ -0,0 +1,368 @@
+/*
+ * Regulator support for WM8400
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ *
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/wm8400-private.h>
+
+static int wm8400_ldo_is_enabled(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+ return (val & WM8400_LDO1_ENA) != 0;
+}
+
+static int wm8400_ldo_enable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_ENA, WM8400_LDO1_ENA);
+}
+
+static int wm8400_ldo_disable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_ENA, 0);
+}
+
+static int wm8400_ldo_get_voltage(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev));
+ val &= WM8400_LDO1_VSEL_MASK;
+
+ if (val < 15)
+ return 900000 + (val * 50000);
+ else
+ return 1600000 + ((val - 14) * 100000);
+}
+
+static int wm8400_ldo_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+
+ if (min_uV < 900000 || min_uV > 3300000)
+ return -EINVAL;
+
+ if (min_uV < 1700000) {
+ /* Steps of 50mV from 900mV; */
+ val = (min_uV - 850001) / 50000;
+
+ if ((val * 50000) + 900000 > max_uV)
+ return -EINVAL;
+ BUG_ON((val * 50000) + 900000 < min_uV);
+ } else {
+ /* Steps of 100mV from 1700mV */
+ val = ((min_uV - 1600001) / 100000);
+
+ if ((val * 100000) + 1700000 > max_uV)
+ return -EINVAL;
+ BUG_ON((val * 100000) + 1700000 < min_uV);
+
+ val += 0xf;
+ }
+
+ return wm8400_set_bits(wm8400, WM8400_LDO1_CONTROL + rdev_get_id(dev),
+ WM8400_LDO1_VSEL_MASK, val);
+}
+
+static struct regulator_ops wm8400_ldo_ops = {
+ .is_enabled = wm8400_ldo_is_enabled,
+ .enable = wm8400_ldo_enable,
+ .disable = wm8400_ldo_disable,
+ .get_voltage = wm8400_ldo_get_voltage,
+ .set_voltage = wm8400_ldo_set_voltage,
+};
+
+static int wm8400_dcdc_is_enabled(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ u16 val;
+
+ val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+ return (val & WM8400_DC1_ENA) != 0;
+}
+
+static int wm8400_dcdc_enable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ENA, WM8400_DC1_ENA);
+}
+
+static int wm8400_dcdc_disable(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ENA, 0);
+}
+
+static int wm8400_dcdc_get_voltage(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ val = wm8400_reg_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset);
+ val &= WM8400_DC1_VSEL_MASK;
+
+ return 850000 + (25000 * val);
+}
+
+static int wm8400_dcdc_set_voltage(struct regulator_dev *dev,
+ int min_uV, int max_uV)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ u16 val;
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+
+ if (min_uV < 850000)
+ return -EINVAL;
+
+ val = (min_uV - 825001) / 25000;
+
+ if (850000 + (25000 * val) > max_uV)
+ return -EINVAL;
+ BUG_ON(850000 + (25000 * val) < min_uV);
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_VSEL_MASK, val);
+}
+
+static unsigned int wm8400_dcdc_get_mode(struct regulator_dev *dev)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ u16 data[2];
+ int ret;
+
+ ret = wm8400_block_read(wm8400, WM8400_DCDC1_CONTROL_1 + offset, 2,
+ data);
+ if (ret != 0)
+ return 0;
+
+ /* Datasheet: hibernate */
+ if (data[0] & WM8400_DC1_SLEEP)
+ return REGULATOR_MODE_STANDBY;
+
+ /* Datasheet: standby */
+ if (!(data[0] & WM8400_DC1_ACTIVE))
+ return REGULATOR_MODE_IDLE;
+
+ /* Datasheet: active with or without force PWM */
+ if (data[1] & WM8400_DC1_FRC_PWM)
+ return REGULATOR_MODE_FAST;
+ else
+ return REGULATOR_MODE_NORMAL;
+}
+
+static int wm8400_dcdc_set_mode(struct regulator_dev *dev, unsigned int mode)
+{
+ struct wm8400 *wm8400 = rdev_get_drvdata(dev);
+ int offset = (rdev_get_id(dev) - WM8400_DCDC1) * 2;
+ int ret;
+
+ switch (mode) {
+ case REGULATOR_MODE_FAST:
+ /* Datasheet: active with force PWM */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+ WM8400_DC1_FRC_PWM, WM8400_DC1_FRC_PWM);
+ if (ret != 0)
+ return ret;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+ WM8400_DC1_ACTIVE);
+
+ case REGULATOR_MODE_NORMAL:
+ /* Datasheet: active */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_2 + offset,
+ WM8400_DC1_FRC_PWM, 0);
+ if (ret != 0)
+ return ret;
+
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE | WM8400_DC1_SLEEP,
+ WM8400_DC1_ACTIVE);
+
+ case REGULATOR_MODE_IDLE:
+ /* Datasheet: standby */
+ ret = wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_ACTIVE, 0);
+ if (ret != 0)
+ return ret;
+ return wm8400_set_bits(wm8400, WM8400_DCDC1_CONTROL_1 + offset,
+ WM8400_DC1_SLEEP, 0);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static unsigned int wm8400_dcdc_get_optimum_mode(struct regulator_dev *dev,
+ int input_uV, int output_uV,
+ int load_uA)
+{
+ return REGULATOR_MODE_NORMAL;
+}
+
+static struct regulator_ops wm8400_dcdc_ops = {
+ .is_enabled = wm8400_dcdc_is_enabled,
+ .enable = wm8400_dcdc_enable,
+ .disable = wm8400_dcdc_disable,
+ .get_voltage = wm8400_dcdc_get_voltage,
+ .set_voltage = wm8400_dcdc_set_voltage,
+ .get_mode = wm8400_dcdc_get_mode,
+ .set_mode = wm8400_dcdc_set_mode,
+ .get_optimum_mode = wm8400_dcdc_get_optimum_mode,
+};
+
+static struct regulator_desc regulators[] = {
+ {
+ .name = "LDO1",
+ .id = WM8400_LDO1,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO2",
+ .id = WM8400_LDO2,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO3",
+ .id = WM8400_LDO3,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "LDO4",
+ .id = WM8400_LDO4,
+ .ops = &wm8400_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC1",
+ .id = WM8400_DCDC1,
+ .ops = &wm8400_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+ {
+ .name = "DCDC2",
+ .id = WM8400_DCDC2,
+ .ops = &wm8400_dcdc_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wm8400_regulator_probe(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev;
+
+ rdev = regulator_register(&regulators[pdev->id], &pdev->dev,
+ pdev->dev.driver_data);
+
+ if (IS_ERR(rdev))
+ return PTR_ERR(rdev);
+
+ return 0;
+}
+
+static int __devexit wm8400_regulator_remove(struct platform_device *pdev)
+{
+ struct regulator_dev *rdev = platform_get_drvdata(pdev);
+
+ regulator_unregister(rdev);
+
+ return 0;
+}
+
+static struct platform_driver wm8400_regulator_driver = {
+ .driver = {
+ .name = "wm8400-regulator",
+ },
+ .probe = wm8400_regulator_probe,
+ .remove = __devexit_p(wm8400_regulator_remove),
+};
+
+/**
+ * wm8400_register_regulator - enable software control of a WM8400 regulator
+ *
+ * This function enables software control of a WM8400 regulator via
+ * the regulator API. It is intended to be called from the
+ * platform_init() callback of the WM8400 MFD driver.
+ *
+ * @param dev The WM8400 device to operate on.
+ * @param reg The regulator to control.
+ * @param initdata Regulator initdata for the regulator.
+ */
+int wm8400_register_regulator(struct device *dev, int reg,
+ struct regulator_init_data *initdata)
+{
+ struct wm8400 *wm8400 = dev->driver_data;
+
+ if (wm8400->regulators[reg].name)
+ return -EBUSY;
+
+ initdata->driver_data = wm8400;
+
+ wm8400->regulators[reg].name = "wm8400-regulator";
+ wm8400->regulators[reg].id = reg;
+ wm8400->regulators[reg].dev.parent = dev;
+ wm8400->regulators[reg].dev.driver_data = wm8400;
+ wm8400->regulators[reg].dev.platform_data = initdata;
+
+ return platform_device_register(&wm8400->regulators[reg]);
+}
+EXPORT_SYMBOL_GPL(wm8400_register_regulator);
+
+static int __init wm8400_regulator_init(void)
+{
+ return platform_driver_register(&wm8400_regulator_driver);
+}
+module_init(wm8400_regulator_init);
+
+static void __exit wm8400_regulator_exit(void)
+{
+ platform_driver_unregister(&wm8400_regulator_driver);
+}
+module_exit(wm8400_regulator_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("WM8400 regulator driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:wm8400-regulator");
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index b57fba5c6d0..f660ef3e5b2 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -220,22 +220,22 @@ config RTC_DRV_PCF8583
will be called rtc-pcf8583.
config RTC_DRV_M41T80
- tristate "ST M41T80/81/82/83/84/85/87"
+ tristate "ST M41T65/M41T80/81/82/83/84/85/87"
help
- If you say Y here you will get support for the
- ST M41T80 RTC chips series. Currently following chips are
- supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85
- and M41ST87.
+ If you say Y here you will get support for the ST M41T60
+ and M41T80 RTC chips series. Currently, the following chips are
+ supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
+ M41ST85, and M41ST87.
This driver can also be built as a module. If so, the module
will be called rtc-m41t80.
config RTC_DRV_M41T80_WDT
- bool "ST M41T80 series RTC watchdog timer"
+ bool "ST M41T65/M41T80 series RTC watchdog timer"
depends on RTC_DRV_M41T80
help
If you say Y here you will get support for the
- watchdog timer in ST M41T80 RTC chips series.
+ watchdog timer in the ST M41T60 and M41T80 RTC chips series.
config RTC_DRV_TWL92330
boolean "TI TWL92330/Menelaus"
@@ -319,6 +319,15 @@ config RTC_DRV_RS5C348
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
+config RTC_DRV_DS3234
+ tristate "Maxim/Dallas DS3234"
+ help
+ If you say yes here you get support for the
+ Maxim/Dallas DS3234 SPI RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds3234.
+
endif # SPI_MASTER
comment "Platform RTC drivers"
@@ -352,6 +361,11 @@ config RTC_DRV_DS1216
help
If you say yes here you get support for the Dallas DS1216 RTC chips.
+config RTC_DRV_DS1286
+ tristate "Dallas DS1286"
+ help
+ If you say yes here you get support for the Dallas DS1286 RTC chips.
+
config RTC_DRV_DS1302
tristate "Dallas DS1302"
depends on SH_SECUREEDGE5410
@@ -405,6 +419,15 @@ config RTC_DRV_M48T86
This driver can also be built as a module. If so, the module
will be called rtc-m48t86.
+config RTC_DRV_M48T35
+ tristate "ST M48T35"
+ help
+ If you say Y here you will get support for the
+ ST M48T35 RTC chip.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-m48t35".
+
config RTC_DRV_M48T59
tristate "ST M48T59/M48T08/M48T02"
help
@@ -589,7 +612,7 @@ config RTC_DRV_RS5C313
config RTC_DRV_PPC
tristate "PowerPC machine dependent RTC support"
- depends on PPC_MERGE
+ depends on PPC
help
The PowerPC kernel has machine-specific functions for accessing
the RTC. This exposes that functionality through the generic RTC
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 10f41f85c38..d05928b3ca9 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
+obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
@@ -31,11 +32,13 @@ obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
+obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index 4e888cc8be5..37082616482 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -29,10 +29,10 @@
#include <linux/completion.h>
#include <asm/uaccess.h>
+
#include <mach/at91_rtc.h>
-#define AT91_RTC_FREQ 1
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
static DECLARE_COMPLETION(at91_rtc_updated);
@@ -228,8 +228,6 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
(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;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index b23af0c2a86..963ad0b6a4e 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -913,6 +913,92 @@ static inline int cmos_poweroff(struct device *dev)
* predate even PNPBIOS should set up platform_bus devices.
*/
+#ifdef CONFIG_ACPI
+
+#include <linux/acpi.h>
+
+#ifdef CONFIG_PM
+static u32 rtc_handler(void *context)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static inline void rtc_wake_setup(void)
+{
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ /*
+ * After the RTC handler is installed, the Fixed_RTC event should
+ * be disabled. Only when the RTC alarm is set will it be enabled.
+ */
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_on(struct device *dev)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_enable_event(ACPI_EVENT_RTC, 0);
+}
+
+static void rtc_wake_off(struct device *dev)
+{
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+}
+#else
+#define rtc_wake_setup() do{}while(0)
+#define rtc_wake_on NULL
+#define rtc_wake_off NULL
+#endif
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
+ * its device node and pass extra config data. This helps its driver use
+ * capabilities that the now-obsolete mc146818 didn't have, and informs it
+ * that this board's RTC is wakeup-capable (per ACPI spec).
+ */
+static struct cmos_rtc_board_info acpi_rtc_info;
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+ if (acpi_disabled)
+ return;
+
+ rtc_wake_setup();
+ acpi_rtc_info.wake_on = rtc_wake_on;
+ acpi_rtc_info.wake_off = rtc_wake_off;
+
+ /* workaround bug in some ACPI tables */
+ if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
+ dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
+ acpi_gbl_FADT.month_alarm);
+ acpi_gbl_FADT.month_alarm = 0;
+ }
+
+ acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
+ acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
+ acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
+
+ /* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
+ if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
+ dev_info(dev, "RTC can wake from S4\n");
+
+ dev->platform_data = &acpi_rtc_info;
+
+ /* RTC always wakes from S1/S2/S3, and often S4/STD */
+ device_init_wakeup(dev, 1);
+}
+
+#else
+
+static void __devinit
+cmos_wake_setup(struct device *dev)
+{
+}
+
+#endif
+
#ifdef CONFIG_PNP
#include <linux/pnp.h>
@@ -920,6 +1006,8 @@ static inline int cmos_poweroff(struct device *dev)
static int __devinit
cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
+ cmos_wake_setup(&pnp->dev);
+
if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
@@ -997,6 +1085,7 @@ static struct pnp_driver cmos_pnp_driver = {
static int __init cmos_platform_probe(struct platform_device *pdev)
{
+ cmos_wake_setup(&pdev->dev);
return cmos_do_probe(&pdev->dev,
platform_get_resource(pdev, IORESOURCE_IO, 0),
platform_get_irq(pdev, 0));
@@ -1031,29 +1120,32 @@ static struct platform_driver cmos_platform_driver = {
static int __init cmos_init(void)
{
+ int retval = 0;
+
#ifdef CONFIG_PNP
- if (pnp_platform_devices)
- return pnp_register_driver(&cmos_pnp_driver);
- else
- return platform_driver_probe(&cmos_platform_driver,
- cmos_platform_probe);
-#else
- return platform_driver_probe(&cmos_platform_driver,
- cmos_platform_probe);
-#endif /* CONFIG_PNP */
+ pnp_register_driver(&cmos_pnp_driver);
+#endif
+
+ if (!cmos_rtc.dev)
+ retval = platform_driver_probe(&cmos_platform_driver,
+ cmos_platform_probe);
+
+ if (retval == 0)
+ return 0;
+
+#ifdef CONFIG_PNP
+ pnp_unregister_driver(&cmos_pnp_driver);
+#endif
+ return retval;
}
module_init(cmos_init);
static void __exit cmos_exit(void)
{
#ifdef CONFIG_PNP
- if (pnp_platform_devices)
- pnp_unregister_driver(&cmos_pnp_driver);
- else
- platform_driver_unregister(&cmos_platform_driver);
-#else
+ pnp_unregister_driver(&cmos_pnp_driver);
+#endif
platform_driver_unregister(&cmos_platform_driver);
-#endif /* CONFIG_PNP */
}
module_exit(cmos_exit);
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 52e2743b04e..079e9ed907e 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -432,9 +432,15 @@ static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = file->private_data;
-#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
- clear_uie(rtc);
-#endif
+ /* We shut down the repeating IRQs that userspace enabled,
+ * since nothing is listening to them.
+ * - Update (UIE) ... currently only managed through ioctls
+ * - Periodic (PIE) ... also used through rtc_*() interface calls
+ *
+ * Leave the alarm alone; it may be set to trigger a system wakeup
+ * later, or be used by kernel code, and is a one-shot event anyway.
+ */
+ rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
rtc_irq_set_state(rtc, NULL, 0);
if (rtc->ops->release)
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
new file mode 100644
index 00000000000..4b4c1b6a418
--- /dev/null
+++ b/drivers/rtc/rtc-ds1286.c
@@ -0,0 +1,409 @@
+/*
+ * DS1286 Real Time Clock interface for Linux
+ *
+ * Copyright (C) 1998, 1999, 2000 Ralf Baechle
+ * Copyright (C) 2008 Thomas Bogendoerfer
+ *
+ * Based on code written 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/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+#include <linux/ds1286.h>
+
+#define DRV_VERSION "1.0"
+
+struct ds1286_priv {
+ struct rtc_device *rtc;
+ u32 __iomem *rtcregs;
+ size_t size;
+ unsigned long baseaddr;
+ spinlock_t lock;
+};
+
+static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg)
+{
+ return __raw_readl(&priv->rtcregs[reg]) & 0xff;
+}
+
+static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
+{
+ __raw_writel(data, &priv->rtcregs[reg]);
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+
+static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned long flags;
+ unsigned char val;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ /* Mask alarm int. enab. bit */
+ spin_lock_irqsave(&priv->lock, flags);
+ val = ds1286_rtc_read(priv, RTC_CMD);
+ val |= RTC_TDM;
+ ds1286_rtc_write(priv, val, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ break;
+ case RTC_AIE_ON:
+ /* Allow alarm interrupts. */
+ spin_lock_irqsave(&priv->lock, flags);
+ val = ds1286_rtc_read(priv, RTC_CMD);
+ val &= ~RTC_TDM;
+ ds1286_rtc_write(priv, val, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ break;
+ case RTC_WIE_OFF:
+ /* Mask watchdog int. enab. bit */
+ spin_lock_irqsave(&priv->lock, flags);
+ val = ds1286_rtc_read(priv, RTC_CMD);
+ val |= RTC_WAM;
+ ds1286_rtc_write(priv, val, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ break;
+ case RTC_WIE_ON:
+ /* Allow watchdog interrupts. */
+ spin_lock_irqsave(&priv->lock, flags);
+ val = ds1286_rtc_read(priv, RTC_CMD);
+ val &= ~RTC_WAM;
+ ds1286_rtc_write(priv, val, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ return 0;
+}
+
+#else
+#define ds1286_ioctl NULL
+#endif
+
+#ifdef CONFIG_PROC_FS
+
+static int ds1286_proc(struct device *dev, struct seq_file *seq)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned char month, cmd, amode;
+ const char *s;
+
+ month = ds1286_rtc_read(priv, RTC_MONTH);
+ seq_printf(seq,
+ "oscillator\t: %s\n"
+ "square_wave\t: %s\n",
+ (month & RTC_EOSC) ? "disabled" : "enabled",
+ (month & RTC_ESQW) ? "disabled" : "enabled");
+
+ amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) |
+ ((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) |
+ ((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7);
+ switch (amode) {
+ case 7:
+ s = "each minute";
+ break;
+ case 3:
+ s = "minutes match";
+ break;
+ case 1:
+ s = "hours and minutes match";
+ break;
+ case 0:
+ s = "days, hours and minutes match";
+ break;
+ default:
+ s = "invalid";
+ break;
+ }
+ seq_printf(seq, "alarm_mode\t: %s\n", s);
+
+ cmd = ds1286_rtc_read(priv, RTC_CMD);
+ seq_printf(seq,
+ "alarm_enable\t: %s\n"
+ "wdog_alarm\t: %s\n"
+ "alarm_mask\t: %s\n"
+ "wdog_alarm_mask\t: %s\n"
+ "interrupt_mode\t: %s\n"
+ "INTB_mode\t: %s_active\n"
+ "interrupt_pins\t: %s\n",
+ (cmd & RTC_TDF) ? "yes" : "no",
+ (cmd & RTC_WAF) ? "yes" : "no",
+ (cmd & RTC_TDM) ? "disabled" : "enabled",
+ (cmd & RTC_WAM) ? "disabled" : "enabled",
+ (cmd & RTC_PU_LVL) ? "pulse" : "level",
+ (cmd & RTC_IBH_LO) ? "low" : "high",
+ (cmd & RTC_IPSW) ? "unswapped" : "swapped");
+ return 0;
+}
+
+#else
+#define ds1286_proc NULL
+#endif
+
+static int ds1286_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned char save_control;
+ unsigned long flags;
+ unsigned long uip_watchdog = jiffies;
+
+ /*
+ * read RTC once any update in progress is done. The update
+ * can take just over 2ms. We wait 10 to 20ms. There is no need to
+ * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
+ * If you need to know *exactly* when a second has started, enable
+ * periodic update complete interrupts, (via ioctl) and then
+ * immediately read /dev/rtc which will block until you get the IRQ.
+ * Once the read clears, read the RTC time (again via ioctl). Easy.
+ */
+
+ if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE)
+ while (time_before(jiffies, uip_watchdog + 2*HZ/100))
+ barrier();
+
+ /*
+ * Only the values that we read from the RTC are set. We leave
+ * tm_wday, tm_yday and tm_isdst untouched. Even though the
+ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+ * by the RTC when initially set to a non-zero value.
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ save_control = ds1286_rtc_read(priv, RTC_CMD);
+ ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
+
+ tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS);
+ tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES);
+ tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f;
+ tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE);
+ tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f;
+ tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR);
+
+ ds1286_rtc_write(priv, save_control, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon);
+ tm->tm_year = bcd2bin(tm->tm_year);
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ if (tm->tm_year < 45)
+ tm->tm_year += 30;
+ tm->tm_year += 40;
+ if (tm->tm_year < 70)
+ tm->tm_year += 100;
+
+ tm->tm_mon--;
+
+ return rtc_valid_tm(tm);
+}
+
+static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned char mon, day, hrs, min, sec;
+ unsigned char save_control;
+ unsigned int yrs;
+ unsigned long flags;
+
+ yrs = tm->tm_year + 1900;
+ mon = tm->tm_mon + 1; /* tm_mon starts at zero */
+ day = tm->tm_mday;
+ hrs = tm->tm_hour;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ if (yrs < 1970)
+ return -EINVAL;
+
+ yrs -= 1940;
+ if (yrs > 255) /* They are unsigned */
+ return -EINVAL;
+
+ if (yrs >= 100)
+ yrs -= 100;
+
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ save_control = ds1286_rtc_read(priv, RTC_CMD);
+ ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
+
+ ds1286_rtc_write(priv, yrs, RTC_YEAR);
+ ds1286_rtc_write(priv, mon, RTC_MONTH);
+ ds1286_rtc_write(priv, day, RTC_DATE);
+ ds1286_rtc_write(priv, hrs, RTC_HOURS);
+ ds1286_rtc_write(priv, min, RTC_MINUTES);
+ ds1286_rtc_write(priv, sec, RTC_SECONDS);
+ ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND);
+
+ ds1286_rtc_write(priv, save_control, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned char cmd;
+ unsigned long flags;
+
+ /*
+ * Only the values that we read from the RTC are set. That
+ * means only tm_wday, tm_hour, tm_min.
+ */
+ spin_lock_irqsave(&priv->lock, flags);
+ alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
+ alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f;
+ alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07;
+ cmd = ds1286_rtc_read(priv, RTC_CMD);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ alm->time.tm_min = bcd2bin(alm->time.tm_min);
+ alm->time.tm_hour = bcd2bin(alm->time.tm_hour);
+ alm->time.tm_sec = 0;
+ return 0;
+}
+
+static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+ struct ds1286_priv *priv = dev_get_drvdata(dev);
+ unsigned char hrs, min, sec;
+
+ hrs = alm->time.tm_hour;
+ min = alm->time.tm_min;
+ sec = alm->time.tm_sec;
+
+ if (hrs >= 24)
+ hrs = 0xff;
+
+ if (min >= 60)
+ min = 0xff;
+
+ if (sec != 0)
+ return -EINVAL;
+
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+
+ spin_lock(&priv->lock);
+ ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM);
+ ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM);
+ spin_unlock(&priv->lock);
+
+ return 0;
+}
+
+static const struct rtc_class_ops ds1286_ops = {
+ .ioctl = ds1286_ioctl,
+ .proc = ds1286_proc,
+ .read_time = ds1286_read_time,
+ .set_time = ds1286_set_time,
+ .read_alarm = ds1286_read_alarm,
+ .set_alarm = ds1286_set_alarm,
+};
+
+static int __devinit ds1286_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ struct ds1286_priv *priv;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->size = res->end - res->start + 1;
+ if (!request_mem_region(res->start, priv->size, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+ priv->baseaddr = res->start;
+ priv->rtcregs = ioremap(priv->baseaddr, priv->size);
+ if (!priv->rtcregs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&priv->lock);
+ rtc = rtc_device_register("ds1286", &pdev->dev,
+ &ds1286_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ priv->rtc = rtc;
+ platform_set_drvdata(pdev, priv);
+ return 0;
+
+out:
+ if (priv->rtc)
+ rtc_device_unregister(priv->rtc);
+ if (priv->rtcregs)
+ iounmap(priv->rtcregs);
+ if (priv->baseaddr)
+ release_mem_region(priv->baseaddr, priv->size);
+ kfree(priv);
+ return ret;
+}
+
+static int __devexit ds1286_remove(struct platform_device *pdev)
+{
+ struct ds1286_priv *priv = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->rtcregs);
+ release_mem_region(priv->baseaddr, priv->size);
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver ds1286_platform_driver = {
+ .driver = {
+ .name = "rtc-ds1286",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1286_probe,
+ .remove = __devexit_p(ds1286_remove),
+};
+
+static int __init ds1286_init(void)
+{
+ return platform_driver_register(&ds1286_platform_driver);
+}
+
+static void __exit ds1286_exit(void)
+{
+ platform_driver_unregister(&ds1286_platform_driver);
+}
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("DS1286 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-ds1286");
+
+module_init(ds1286_init);
+module_exit(ds1286_exit);
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bbf97e65202..4fcf0734a6e 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -23,10 +23,6 @@
* 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.
- *
- * This is currently a simple no-alarms driver. If your board has the
- * alarm irq wired up on a ds1337 or ds1339, and you want to use that,
- * then look at the rtc-rs5c372 driver for code to steal...
*/
enum ds_type {
ds_1307,
@@ -67,6 +63,7 @@ enum ds_type {
# define DS1307_BIT_RS0 0x01
#define DS1337_REG_CONTROL 0x0e
# define DS1337_BIT_nEOSC 0x80
+# define DS1339_BIT_BBSQI 0x20
# define DS1337_BIT_RS2 0x10
# define DS1337_BIT_RS1 0x08
# define DS1337_BIT_INTCN 0x04
@@ -83,19 +80,22 @@ enum ds_type {
# define DS1337_BIT_OSF 0x80
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
+#define DS1339_REG_ALARM1_SECS 0x07
#define DS1339_REG_TRICKLE 0x10
struct ds1307 {
u8 reg_addr;
- bool has_nvram;
- u8 regs[8];
+ u8 regs[11];
enum ds_type type;
+ unsigned long flags;
+#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
+#define HAS_ALARM 1 /* bit 1 == irq claimed */
struct i2c_msg msg[2];
struct i2c_client *client;
- struct i2c_client dev;
struct rtc_device *rtc;
+ struct work_struct work;
};
struct chip_desc {
@@ -132,12 +132,79 @@ static const struct i2c_device_id ds1307_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
+/*----------------------------------------------------------------------*/
+
+/*
+ * The IRQ logic includes a "real" handler running in IRQ context just
+ * long enough to schedule this workqueue entry. We need a task context
+ * to talk to the RTC, since I2C I/O calls require that; and disable the
+ * IRQ until we clear its status on the chip, so that this handler can
+ * work with any type of triggering (not just falling edge).
+ *
+ * The ds1337 and ds1339 both have two alarms, but we only use the first
+ * one (with a "seconds" field). For ds1337 we expect nINTA is our alarm
+ * signal; ds1339 chips have only one alarm signal.
+ */
+static void ds1307_work(struct work_struct *work)
+{
+ struct ds1307 *ds1307;
+ struct i2c_client *client;
+ struct mutex *lock;
+ int stat, control;
+
+ ds1307 = container_of(work, struct ds1307, work);
+ client = ds1307->client;
+ lock = &ds1307->rtc->ops_lock;
+
+ mutex_lock(lock);
+ stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
+ if (stat < 0)
+ goto out;
+
+ if (stat & DS1337_BIT_A1I) {
+ stat &= ~DS1337_BIT_A1I;
+ i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat);
+
+ control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (control < 0)
+ goto out;
+
+ control &= ~DS1337_BIT_A1IE;
+ i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
+
+ /* rtc_update_irq() assumes that it is called
+ * from IRQ-disabled context.
+ */
+ local_irq_disable();
+ rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+ local_irq_enable();
+ }
+
+out:
+ if (test_bit(HAS_ALARM, &ds1307->flags))
+ enable_irq(client->irq);
+ mutex_unlock(lock);
+}
+
+static irqreturn_t ds1307_irq(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+
+ disable_irq_nosync(irq);
+ schedule_work(&ds1307->work);
+ return IRQ_HANDLED;
+}
+
+/*----------------------------------------------------------------------*/
+
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
int tmp;
/* read the RTC date and time registers all at once */
+ ds1307->reg_addr = 0;
ds1307->msg[1].flags = I2C_M_RD;
ds1307->msg[1].len = 7;
@@ -231,9 +298,186 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
return 0;
}
+static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ /* read all ALARM1, ALARM2, and status registers at once */
+ ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 9;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ ds1307->msg, 2);
+ if (ret != 2) {
+ dev_err(dev, "%s error %d\n", "alarm read", ret);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+ "alarm read",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6], ds1307->regs[7],
+ ds1307->regs[8]);
+
+ /* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+ * and that all four fields are checked matches
+ */
+ t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
+ t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
+ t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
+ t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
+ t->time.tm_mon = -1;
+ t->time.tm_year = -1;
+ t->time.tm_wday = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+
+ /* ... and status */
+ t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
+ t->pending = !!(ds1307->regs[8] & DS1337_BIT_A1I);
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+ "alarm read", t->time.tm_sec, t->time.tm_min,
+ t->time.tm_hour, t->time.tm_mday,
+ t->enabled, t->pending);
+
+ return 0;
+}
+
+static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ unsigned char *buf = ds1307->regs;
+ u8 control, status;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s secs=%d, mins=%d, "
+ "hours=%d, mday=%d, enabled=%d, pending=%d\n",
+ "alarm set", t->time.tm_sec, t->time.tm_min,
+ t->time.tm_hour, t->time.tm_mday,
+ t->enabled, t->pending);
+
+ /* read current status of both alarms and the chip */
+ ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
+ ds1307->msg[1].flags = I2C_M_RD;
+ ds1307->msg[1].len = 9;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ ds1307->msg, 2);
+ if (ret != 2) {
+ dev_err(dev, "%s error %d\n", "alarm write", ret);
+ return -EIO;
+ }
+ control = ds1307->regs[7];
+ status = ds1307->regs[8];
+
+ dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
+ "alarm set (old status)",
+ ds1307->regs[0], ds1307->regs[1],
+ ds1307->regs[2], ds1307->regs[3],
+ ds1307->regs[4], ds1307->regs[5],
+ ds1307->regs[6], control, status);
+
+ /* set ALARM1, using 24 hour and day-of-month modes */
+ *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */
+ buf[0] = bin2bcd(t->time.tm_sec);
+ buf[1] = bin2bcd(t->time.tm_min);
+ buf[2] = bin2bcd(t->time.tm_hour);
+ buf[3] = bin2bcd(t->time.tm_mday);
+
+ /* set ALARM2 to non-garbage */
+ buf[4] = 0;
+ buf[5] = 0;
+ buf[6] = 0;
+
+ /* optionally enable ALARM1 */
+ buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
+ if (t->enabled) {
+ dev_dbg(dev, "alarm IRQ armed\n");
+ buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
+ }
+ buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
+
+ ds1307->msg[1].flags = 0;
+ ds1307->msg[1].len = 10;
+
+ ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
+ &ds1307->msg[1], 1);
+ if (ret != 1) {
+ dev_err(dev, "can't set alarm time\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int ret;
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -ENOTTY;
+
+ ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~DS1337_BIT_A1IE;
+
+ ret = i2c_smbus_write_byte_data(client,
+ DS1337_REG_CONTROL, ret);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ case RTC_AIE_ON:
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -ENOTTY;
+
+ ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+ if (ret < 0)
+ return ret;
+
+ ret |= DS1337_BIT_A1IE;
+
+ ret = i2c_smbus_write_byte_data(client,
+ DS1337_REG_CONTROL, ret);
+ if (ret < 0)
+ return ret;
+
+ break;
+
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ return 0;
+}
+
static const struct rtc_class_ops ds13xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
+ .read_alarm = ds1307_read_alarm,
+ .set_alarm = ds1307_set_alarm,
+ .ioctl = ds1307_ioctl,
};
/*----------------------------------------------------------------------*/
@@ -327,6 +571,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
int tmp;
const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ int want_irq = false;
if (!i2c_check_functionality(adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
@@ -353,6 +598,12 @@ static int __devinit ds1307_probe(struct i2c_client *client,
switch (ds1307->type) {
case ds_1337:
case ds_1339:
+ /* has IRQ? */
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, ds1307_work);
+ want_irq = true;
+ }
+
ds1307->reg_addr = DS1337_REG_CONTROL;
ds1307->msg[1].len = 2;
@@ -369,8 +620,20 @@ static int __devinit ds1307_probe(struct i2c_client *client,
/* oscillator off? turn it on, so clock can tick. */
if (ds1307->regs[0] & DS1337_BIT_nEOSC)
- i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
- ds1307->regs[0] & ~DS1337_BIT_nEOSC);
+ ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
+
+ /* Using IRQ? Disable the square wave and both alarms.
+ * For ds1339, be sure alarms can trigger when we're
+ * running on Vbackup (BBSQI); we assume ds1337 will
+ * ignore that bit
+ */
+ if (want_irq) {
+ ds1307->regs[0] |= DS1337_BIT_INTCN | DS1339_BIT_BBSQI;
+ ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+ }
+
+ i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
+ ds1307->regs[0]);
/* oscillator fault? clear flag, and warn */
if (ds1307->regs[1] & DS1337_BIT_OSF) {
@@ -495,10 +758,22 @@ read_rtc:
goto exit_free;
}
+ if (want_irq) {
+ err = request_irq(client->irq, ds1307_irq, 0,
+ ds1307->rtc->name, client);
+ if (err) {
+ dev_err(&client->dev,
+ "unable to request IRQ!\n");
+ goto exit_irq;
+ }
+ set_bit(HAS_ALARM, &ds1307->flags);
+ dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ }
+
if (chip->nvram56) {
err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
if (err == 0) {
- ds1307->has_nvram = true;
+ set_bit(HAS_NVRAM, &ds1307->flags);
dev_info(&client->dev, "56 bytes nvram\n");
}
}
@@ -512,7 +787,9 @@ exit_bad:
ds1307->regs[2], ds1307->regs[3],
ds1307->regs[4], ds1307->regs[5],
ds1307->regs[6]);
-
+exit_irq:
+ if (ds1307->rtc)
+ rtc_device_unregister(ds1307->rtc);
exit_free:
kfree(ds1307);
return err;
@@ -520,9 +797,14 @@ exit_free:
static int __devexit ds1307_remove(struct i2c_client *client)
{
- struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+
+ if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
+ free_irq(client->irq, client);
+ cancel_work_sync(&ds1307->work);
+ }
- if (ds1307->has_nvram)
+ if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
sysfs_remove_bin_file(&client->dev.kobj, &nvram);
rtc_device_unregister(ds1307->rtc);
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index a150418fba7..a5b0fc09f0c 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -429,12 +429,33 @@ static int __devexit ds1374_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
+static int ds1374_suspend(struct i2c_client *client, pm_message_t state)
+{
+ if (client->irq >= 0 && device_may_wakeup(&client->dev))
+ enable_irq_wake(client->irq);
+ return 0;
+}
+
+static int ds1374_resume(struct i2c_client *client)
+{
+ if (client->irq >= 0 && device_may_wakeup(&client->dev))
+ disable_irq_wake(client->irq);
+ return 0;
+}
+#else
+#define ds1374_suspend NULL
+#define ds1374_resume NULL
+#endif
+
static struct i2c_driver ds1374_driver = {
.driver = {
.name = "rtc-ds1374",
.owner = THIS_MODULE,
},
.probe = ds1374_probe,
+ .suspend = ds1374_suspend,
+ .resume = ds1374_resume,
.remove = __devexit_p(ds1374_remove),
.id_table = ds1374_id,
};
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 0f0d27d1c4c..86981d34fbb 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -379,18 +379,6 @@ ds1511_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
- static void
-ds1511_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;
- ds1511_rtc_update_alarm(pdata);
- }
-}
-
static int
ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
@@ -428,7 +416,6 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
.set_time = ds1511_rtc_set_time,
.read_alarm = ds1511_rtc_read_alarm,
.set_alarm = ds1511_rtc_set_alarm,
- .release = ds1511_rtc_release,
.ioctl = ds1511_rtc_ioctl,
};
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index a19f1141554..4ef59285b48 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -207,17 +207,6 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
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)
{
@@ -254,7 +243,6 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
.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,
};
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 6fa4556f5f5..341d7a5b45a 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -9,17 +9,10 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
-#define DRV_VERSION "0.3"
-
-/* Addresses to scan: none. This chip cannot be detected. */
-static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
+#define DRV_VERSION "0.4"
/* Registers */
@@ -29,8 +22,7 @@ I2C_CLIENT_INSMOD;
#define DS1672_REG_CONTROL_EOSC 0x80
-/* Prototypes */
-static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
+static struct i2c_driver ds1672_driver;
/*
* In the routines that deal directly with the ds1672 hardware, we use
@@ -44,8 +36,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[4];
struct i2c_msg msgs[] = {
- { client->addr, 0, 1, &addr }, /* setup read ptr */
- { client->addr, I2C_M_RD, 4, buf }, /* read date */
+ {client->addr, 0, 1, &addr}, /* setup read ptr */
+ {client->addr, I2C_M_RD, 4, buf}, /* read date */
};
/* read date registers */
@@ -80,7 +72,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
buf[2] = (secs & 0x0000FF00) >> 8;
buf[3] = (secs & 0x00FF0000) >> 16;
buf[4] = (secs & 0xFF000000) >> 24;
- buf[5] = 0; /* set control reg to enable counting */
+ buf[5] = 0; /* set control reg to enable counting */
xfer = i2c_master_send(client, buf, 6);
if (xfer != 6) {
@@ -127,8 +119,8 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
unsigned char addr = DS1672_REG_CONTROL;
struct i2c_msg msgs[] = {
- { client->addr, 0, 1, &addr }, /* setup read ptr */
- { client->addr, I2C_M_RD, 1, status }, /* read control */
+ {client->addr, 0, 1, &addr}, /* setup read ptr */
+ {client->addr, I2C_M_RD, 1, status}, /* read control */
};
/* read control register */
@@ -141,7 +133,8 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
}
/* following are the sysfs callback functions */
-static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_control(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
u8 control;
@@ -152,85 +145,46 @@ static ssize_t show_control(struct device *dev, struct device_attribute *attr, c
return err;
return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC)
- ? "disabled" : "enabled");
+ ? "disabled" : "enabled");
}
+
static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
static const struct rtc_class_ops ds1672_rtc_ops = {
- .read_time = ds1672_rtc_read_time,
- .set_time = ds1672_rtc_set_time,
- .set_mmss = ds1672_rtc_set_mmss,
+ .read_time = ds1672_rtc_read_time,
+ .set_time = ds1672_rtc_set_time,
+ .set_mmss = ds1672_rtc_set_mmss,
};
-static int ds1672_attach(struct i2c_adapter *adapter)
+static int ds1672_remove(struct i2c_client *client)
{
- return i2c_probe(adapter, &addr_data, ds1672_probe);
-}
-
-static int ds1672_detach(struct i2c_client *client)
-{
- int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
- if (rtc)
+ if (rtc)
rtc_device_unregister(rtc);
- if ((err = i2c_detach_client(client)))
- return err;
-
- kfree(client);
-
return 0;
}
-static struct i2c_driver ds1672_driver = {
- .driver = {
- .name = "ds1672",
- },
- .id = I2C_DRIVERID_DS1672,
- .attach_adapter = &ds1672_attach,
- .detach_client = &ds1672_detach,
-};
-
-static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
+static int ds1672_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
u8 control;
- struct i2c_client *client;
struct rtc_device *rtc;
- dev_dbg(&adapter->dev, "%s\n", __func__);
+ dev_dbg(&client->dev, "%s\n", __func__);
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto exit;
- }
-
- if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
- err = -ENOMEM;
- goto exit;
- }
-
- /* I2C client */
- client->addr = address;
- client->driver = &ds1672_driver;
- client->adapter = adapter;
-
- strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
-
- /* Inform the i2c layer */
- if ((err = i2c_attach_client(client)))
- goto exit_kfree;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
- &ds1672_rtc_ops, THIS_MODULE);
+ &ds1672_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- err = PTR_ERR(rtc);
- goto exit_detach;
- }
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
@@ -241,7 +195,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
if (control & DS1672_REG_CONTROL_EOSC)
dev_warn(&client->dev, "Oscillator not enabled. "
- "Set time to enable.\n");
+ "Set time to enable.\n");
/* Register sysfs hooks */
err = device_create_file(&client->dev, &dev_attr_control);
@@ -250,19 +204,19 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
return 0;
-exit_devreg:
+ exit_devreg:
rtc_device_unregister(rtc);
-
-exit_detach:
- i2c_detach_client(client);
-
-exit_kfree:
- kfree(client);
-
-exit:
return err;
}
+static struct i2c_driver ds1672_driver = {
+ .driver = {
+ .name = "rtc-ds1672",
+ },
+ .probe = &ds1672_probe,
+ .remove = &ds1672_remove,
+};
+
static int __init ds1672_init(void)
{
return i2c_add_driver(&ds1672_driver);
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
new file mode 100644
index 00000000000..37d131d03f3
--- /dev/null
+++ b/drivers/rtc/rtc-ds3234.c
@@ -0,0 +1,290 @@
+/* drivers/rtc/rtc-ds3234.c
+ *
+ * Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
+ * and SRAM.
+ *
+ * Copyright (C) 2008 MIMOMax Wireless 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.
+ *
+ * Changelog:
+ *
+ * 07-May-2008: Dennis Aberilla <denzzzhome@yahoo.com>
+ * - Created based on the max6902 code. Only implements the
+ * date/time keeping functions; no SRAM yet.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/spi/spi.h>
+#include <linux/bcd.h>
+
+#define DS3234_REG_SECONDS 0x00
+#define DS3234_REG_MINUTES 0x01
+#define DS3234_REG_HOURS 0x02
+#define DS3234_REG_DAY 0x03
+#define DS3234_REG_DATE 0x04
+#define DS3234_REG_MONTH 0x05
+#define DS3234_REG_YEAR 0x06
+#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */
+
+#define DS3234_REG_CONTROL 0x0E
+#define DS3234_REG_CONT_STAT 0x0F
+
+#undef DS3234_DEBUG
+
+struct ds3234 {
+ struct rtc_device *rtc;
+ u8 buf[8]; /* Burst read: addr + 7 regs */
+ u8 tx_buf[2];
+ u8 rx_buf[2];
+};
+
+static void ds3234_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 '1' to indicate write */
+ buf[0] = address | 0x80;
+ buf[1] = data;
+
+ spi_write(spi, buf, 2);
+}
+
+static int ds3234_get_reg(struct device *dev, unsigned char address,
+ unsigned char *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct ds3234 *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));
+
+ /* Address + dummy tx byte */
+ xfer.len = 2;
+ xfer.tx_buf = chip->tx_buf;
+ xfer.rx_buf = chip->rx_buf;
+
+ chip->tx_buf[0] = address;
+ chip->tx_buf[1] = 0xff;
+
+ 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 ds3234_get_datetime(struct device *dev, struct rtc_time *dt)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct ds3234 *chip = dev_get_drvdata(dev);
+ struct spi_message message;
+ struct spi_transfer xfer;
+ int status;
+
+ /* build the message */
+ spi_message_init(&message);
+ memset(&xfer, 0, sizeof(xfer));
+ xfer.len = 1 + 7; /* Addr + 7 registers */
+ xfer.tx_buf = chip->buf;
+ xfer.rx_buf = chip->buf;
+ chip->buf[0] = 0x00; /* Start address */
+ spi_message_add_tail(&xfer, &message);
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0)
+ status = message.status;
+ else
+ return status;
+
+ /* Seconds, Minutes, Hours, Day, Date, Month, Year */
+ dt->tm_sec = bcd2bin(chip->buf[1]);
+ dt->tm_min = bcd2bin(chip->buf[2]);
+ dt->tm_hour = bcd2bin(chip->buf[3] & 0x3f);
+ dt->tm_wday = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */
+ dt->tm_mday = bcd2bin(chip->buf[5]);
+ dt->tm_mon = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */
+ dt->tm_year = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */
+
+#ifdef DS3234_DEBUG
+ dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
+ dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+ dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+ dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+ dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+ dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+ dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+ dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+#endif
+
+ return 0;
+}
+
+static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt)
+{
+#ifdef DS3234_DEBUG
+ dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
+ dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
+ dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
+ dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
+ dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
+ dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
+ dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
+ dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
+#endif
+
+ ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
+ ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
+ ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
+
+ /* 0 = Sun */
+ ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
+ ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
+
+ /* 0 = Jan */
+ ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
+
+ /* Assume 20YY although we just want to make sure not to go negative. */
+ if (dt->tm_year > 100)
+ dt->tm_year -= 100;
+
+ ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
+
+ return 0;
+}
+
+static int ds3234_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return ds3234_get_datetime(dev, tm);
+}
+
+static int ds3234_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return ds3234_set_datetime(dev, tm);
+}
+
+static const struct rtc_class_ops ds3234_rtc_ops = {
+ .read_time = ds3234_read_time,
+ .set_time = ds3234_set_time,
+};
+
+static int ds3234_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char tmp;
+ struct ds3234 *chip;
+ int res;
+
+ rtc = rtc_device_register("ds3234",
+ &spi->dev, &ds3234_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(struct ds3234), GFP_KERNEL);
+ if (!chip) {
+ rtc_device_unregister(rtc);
+ return -ENOMEM;
+ }
+ chip->rtc = rtc;
+ dev_set_drvdata(&spi->dev, chip);
+
+ res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
+ if (res) {
+ rtc_device_unregister(rtc);
+ return res;
+ }
+
+ /* Control settings
+ *
+ * CONTROL_REG
+ * BIT 7 6 5 4 3 2 1 0
+ * EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
+ *
+ * 0 0 0 1 1 1 0 0
+ *
+ * CONTROL_STAT_REG
+ * BIT 7 6 5 4 3 2 1 0
+ * OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
+ *
+ * 1 0 0 0 1 0 0 0
+ */
+ ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
+ ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
+
+ ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
+ ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
+
+ /* Print our settings */
+ ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
+ dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
+
+ ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
+ dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
+
+ return 0;
+}
+
+static int __exit ds3234_remove(struct spi_device *spi)
+{
+ struct ds3234 *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 ds3234_driver = {
+ .driver = {
+ .name = "ds3234",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = ds3234_probe,
+ .remove = __devexit_p(ds3234_remove),
+};
+
+static __init int ds3234_init(void)
+{
+ printk(KERN_INFO "DS3234 SPI RTC Driver\n");
+ return spi_register_driver(&ds3234_driver);
+}
+module_init(ds3234_init);
+
+static __exit void ds3234_exit(void)
+{
+ spi_unregister_driver(&ds3234_driver);
+}
+module_exit(ds3234_exit);
+
+MODULE_DESCRIPTION("DS3234 SPI RTC driver");
+MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 24bc1689fc7..470fb2d2954 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -56,21 +56,27 @@
#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
#define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
#define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
+#define M41T80_WATCHDOG_RB2 (1 << 7) /* RB: Watchdog resolution */
+#define M41T80_WATCHDOG_RB1 (1 << 1) /* RB: Watchdog resolution */
+#define M41T80_WATCHDOG_RB0 (1 << 0) /* RB: Watchdog resolution */
-#define M41T80_FEATURE_HT (1 << 0)
-#define M41T80_FEATURE_BL (1 << 1)
+#define M41T80_FEATURE_HT (1 << 0) /* Halt feature */
+#define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */
+#define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */
+#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */
#define DRV_VERSION "0.05"
static const struct i2c_device_id m41t80_id[] = {
- { "m41t80", 0 },
- { "m41t81", M41T80_FEATURE_HT },
- { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
- { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
- { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
- { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
- { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
- { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
+ { "m41t80", M41T80_FEATURE_SQ },
+ { "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
+ { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
+ { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ }
};
MODULE_DEVICE_TABLE(i2c, m41t80_id);
@@ -386,8 +392,12 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct m41t80_data *clientdata = i2c_get_clientdata(client);
int val;
+ if (!(clientdata->features & M41T80_FEATURE_SQ))
+ return -EINVAL;
+
val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
if (val < 0)
return -EIO;
@@ -408,9 +418,13 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
+ struct m41t80_data *clientdata = i2c_get_clientdata(client);
int almon, sqw;
int val = simple_strtoul(buf, NULL, 0);
+ if (!(clientdata->features & M41T80_FEATURE_SQ))
+ return -EINVAL;
+
if (val) {
if (!is_power_of_2(val))
return -EINVAL;
@@ -499,6 +513,8 @@ static void wdt_ping(void)
.buf = i2c_data,
},
};
+ struct m41t80_data *clientdata = i2c_get_clientdata(save_client);
+
i2c_data[0] = 0x09; /* watchdog register */
if (wdt_margin > 31)
@@ -509,6 +525,13 @@ static void wdt_ping(void)
*/
i2c_data[1] = wdt_margin<<2 | 0x82;
+ /*
+ * M41T65 has three bits for watchdog resolution. Don't set bit 7, as
+ * that would be an invalid resolution.
+ */
+ if (clientdata->features & M41T80_FEATURE_WD)
+ i2c_data[1] &= ~M41T80_WATCHDOG_RB2;
+
i2c_transfer(save_client->adapter, msgs1, 1);
}
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
new file mode 100644
index 00000000000..b9c1fe4a198
--- /dev/null
+++ b/drivers/rtc/rtc-m48t35.c
@@ -0,0 +1,234 @@
+/*
+ * Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
+ *
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Written by Ulf Carlsson (ulfc@engr.sgi.com)
+ *
+ * Copyright (C) 2008 Thomas Bogendoerfer
+ *
+ * Based on code written 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/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/bcd.h>
+
+#define DRV_VERSION "1.0"
+
+struct m48t35_rtc {
+ u8 pad[0x7ff8]; /* starts at 0x7ff8 */
+ u8 control;
+ u8 sec;
+ u8 min;
+ u8 hour;
+ u8 day;
+ u8 date;
+ u8 month;
+ u8 year;
+};
+
+#define M48T35_RTC_SET 0x80
+#define M48T35_RTC_READ 0x40
+
+struct m48t35_priv {
+ struct rtc_device *rtc;
+ struct m48t35_rtc __iomem *reg;
+ size_t size;
+ unsigned long baseaddr;
+ spinlock_t lock;
+};
+
+static int m48t35_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct m48t35_priv *priv = dev_get_drvdata(dev);
+ u8 control;
+
+ /*
+ * Only the values that we read from the RTC are set. We leave
+ * tm_wday, tm_yday and tm_isdst untouched. Even though the
+ * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
+ * by the RTC when initially set to a non-zero value.
+ */
+ spin_lock_irq(&priv->lock);
+ control = readb(&priv->reg->control);
+ writeb(control | M48T35_RTC_READ, &priv->reg->control);
+ tm->tm_sec = readb(&priv->reg->sec);
+ tm->tm_min = readb(&priv->reg->min);
+ tm->tm_hour = readb(&priv->reg->hour);
+ tm->tm_mday = readb(&priv->reg->date);
+ tm->tm_mon = readb(&priv->reg->month);
+ tm->tm_year = readb(&priv->reg->year);
+ writeb(control, &priv->reg->control);
+ spin_unlock_irq(&priv->lock);
+
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon);
+ tm->tm_year = bcd2bin(tm->tm_year);
+
+ /*
+ * Account for differences between how the RTC uses the values
+ * and how they are defined in a struct rtc_time;
+ */
+ tm->tm_year += 70;
+ if (tm->tm_year <= 69)
+ tm->tm_year += 100;
+
+ tm->tm_mon--;
+ return rtc_valid_tm(tm);
+}
+
+static int m48t35_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct m48t35_priv *priv = dev_get_drvdata(dev);
+ unsigned char mon, day, hrs, min, sec;
+ unsigned int yrs;
+ u8 control;
+
+ yrs = tm->tm_year + 1900;
+ mon = tm->tm_mon + 1; /* tm_mon starts at zero */
+ day = tm->tm_mday;
+ hrs = tm->tm_hour;
+ min = tm->tm_min;
+ sec = tm->tm_sec;
+
+ if (yrs < 1970)
+ return -EINVAL;
+
+ yrs -= 1970;
+ if (yrs > 255) /* They are unsigned */
+ return -EINVAL;
+
+ if (yrs > 169)
+ return -EINVAL;
+
+ if (yrs >= 100)
+ yrs -= 100;
+
+ sec = bin2bcd(sec);
+ min = bin2bcd(min);
+ hrs = bin2bcd(hrs);
+ day = bin2bcd(day);
+ mon = bin2bcd(mon);
+ yrs = bin2bcd(yrs);
+
+ spin_lock_irq(&priv->lock);
+ control = readb(&priv->reg->control);
+ writeb(control | M48T35_RTC_SET, &priv->reg->control);
+ writeb(yrs, &priv->reg->year);
+ writeb(mon, &priv->reg->month);
+ writeb(day, &priv->reg->date);
+ writeb(hrs, &priv->reg->hour);
+ writeb(min, &priv->reg->min);
+ writeb(sec, &priv->reg->sec);
+ writeb(control, &priv->reg->control);
+ spin_unlock_irq(&priv->lock);
+ return 0;
+}
+
+static const struct rtc_class_ops m48t35_ops = {
+ .read_time = m48t35_read_time,
+ .set_time = m48t35_set_time,
+};
+
+static int __devinit m48t35_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct resource *res;
+ struct m48t35_priv *priv;
+ int ret = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ priv = kzalloc(sizeof(struct m48t35_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->size = res->end - res->start + 1;
+ /*
+ * kludge: remove the #ifndef after ioc3 resource
+ * conflicts are resolved
+ */
+#ifndef CONFIG_SGI_IP27
+ if (!request_mem_region(res->start, priv->size, pdev->name)) {
+ ret = -EBUSY;
+ goto out;
+ }
+#endif
+ priv->baseaddr = res->start;
+ priv->reg = ioremap(priv->baseaddr, priv->size);
+ if (!priv->reg) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&priv->lock);
+ rtc = rtc_device_register("m48t35", &pdev->dev,
+ &m48t35_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc);
+ goto out;
+ }
+ priv->rtc = rtc;
+ platform_set_drvdata(pdev, priv);
+ return 0;
+
+out:
+ if (priv->rtc)
+ rtc_device_unregister(priv->rtc);
+ if (priv->reg)
+ iounmap(priv->reg);
+ if (priv->baseaddr)
+ release_mem_region(priv->baseaddr, priv->size);
+ kfree(priv);
+ return ret;
+}
+
+static int __devexit m48t35_remove(struct platform_device *pdev)
+{
+ struct m48t35_priv *priv = platform_get_drvdata(pdev);
+
+ rtc_device_unregister(priv->rtc);
+ iounmap(priv->reg);
+#ifndef CONFIG_SGI_IP27
+ release_mem_region(priv->baseaddr, priv->size);
+#endif
+ kfree(priv);
+ return 0;
+}
+
+static struct platform_driver m48t35_platform_driver = {
+ .driver = {
+ .name = "rtc-m48t35",
+ .owner = THIS_MODULE,
+ },
+ .probe = m48t35_probe,
+ .remove = __devexit_p(m48t35_remove),
+};
+
+static int __init m48t35_init(void)
+{
+ return platform_driver_register(&m48t35_platform_driver);
+}
+
+static void __exit m48t35_exit(void)
+{
+ platform_driver_unregister(&m48t35_platform_driver);
+}
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
+MODULE_DESCRIPTION("M48T35 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-m48t35");
+
+module_init(m48t35_init);
+module_exit(m48t35_exit);
diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c
index ded3c0abad8..12c9cd25cad 100644
--- a/drivers/rtc/rtc-max6900.c
+++ b/drivers/rtc/rtc-max6900.c
@@ -17,19 +17,18 @@
#include <linux/rtc.h>
#include <linux/delay.h>
-#define DRV_NAME "max6900"
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
/*
* register indices
*/
-#define MAX6900_REG_SC 0 /* seconds 00-59 */
-#define MAX6900_REG_MN 1 /* minutes 00-59 */
-#define MAX6900_REG_HR 2 /* hours 00-23 */
-#define MAX6900_REG_DT 3 /* day of month 00-31 */
-#define MAX6900_REG_MO 4 /* month 01-12 */
-#define MAX6900_REG_DW 5 /* day of week 1-7 */
-#define MAX6900_REG_YR 6 /* year 00-99 */
+#define MAX6900_REG_SC 0 /* seconds 00-59 */
+#define MAX6900_REG_MN 1 /* minutes 00-59 */
+#define MAX6900_REG_HR 2 /* hours 00-23 */
+#define MAX6900_REG_DT 3 /* day of month 00-31 */
+#define MAX6900_REG_MO 4 /* month 01-12 */
+#define MAX6900_REG_DW 5 /* day of week 1-7 */
+#define MAX6900_REG_YR 6 /* year 00-99 */
#define MAX6900_REG_CT 7 /* control */
/* register 8 is undocumented */
#define MAX6900_REG_CENTURY 9 /* century */
@@ -39,7 +38,6 @@
#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
-
/*
* register read/write commands
*/
@@ -52,16 +50,7 @@
#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
-#define MAX6900_I2C_ADDR 0xa0
-
-static const unsigned short normal_i2c[] = {
- MAX6900_I2C_ADDR >> 1,
- I2C_CLIENT_END
-};
-
-I2C_CLIENT_INSMOD; /* defines addr_data */
-
-static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
+static struct i2c_driver max6900_driver;
static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
{
@@ -69,36 +58,35 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
struct i2c_msg msgs[4] = {
{
- .addr = client->addr,
- .flags = 0, /* write */
- .len = sizeof(reg_burst_read),
- .buf = reg_burst_read
- },
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(reg_burst_read),
+ .buf = reg_burst_read}
+ ,
{
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = MAX6900_BURST_LEN,
- .buf = buf
- },
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = MAX6900_BURST_LEN,
+ .buf = buf}
+ ,
{
- .addr = client->addr,
- .flags = 0, /* write */
- .len = sizeof(reg_century_read),
- .buf = reg_century_read
- },
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(reg_century_read),
+ .buf = reg_century_read}
+ ,
{
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = sizeof(buf[MAX6900_REG_CENTURY]),
- .buf = &buf[MAX6900_REG_CENTURY]
- }
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf[MAX6900_REG_CENTURY]),
+ .buf = &buf[MAX6900_REG_CENTURY]
+ }
};
int rc;
rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (rc != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev, "%s: register read failed\n",
- __func__);
+ dev_err(&client->dev, "%s: register read failed\n", __func__);
return -EIO;
}
return 0;
@@ -109,20 +97,18 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
struct i2c_msg century_msgs[1] = {
{
- .addr = client->addr,
- .flags = 0, /* write */
- .len = sizeof(i2c_century_buf),
- .buf = i2c_century_buf
- }
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(i2c_century_buf),
+ .buf = i2c_century_buf}
};
u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
struct i2c_msg burst_msgs[1] = {
{
- .addr = client->addr,
- .flags = 0, /* write */
- .len = sizeof(i2c_burst_buf),
- .buf = i2c_burst_buf
- }
+ .addr = client->addr,
+ .flags = 0, /* write */
+ .len = sizeof(i2c_burst_buf),
+ .buf = i2c_burst_buf}
};
int rc;
@@ -133,10 +119,12 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
* bit as part of the burst write.
*/
i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
+
rc = i2c_transfer(client->adapter, century_msgs,
ARRAY_SIZE(century_msgs));
if (rc != ARRAY_SIZE(century_msgs))
goto write_failed;
+
msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
@@ -148,45 +136,11 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
return 0;
-write_failed:
- dev_err(&client->dev, "%s: register write failed\n",
- __func__);
+ write_failed:
+ dev_err(&client->dev, "%s: register write failed\n", __func__);
return -EIO;
}
-static int max6900_i2c_validate_client(struct i2c_client *client)
-{
- u8 regs[MAX6900_REG_LEN];
- u8 zero_mask[] = {
- 0x80, /* seconds */
- 0x80, /* minutes */
- 0x40, /* hours */
- 0xc0, /* day of month */
- 0xe0, /* month */
- 0xf8, /* day of week */
- 0x00, /* year */
- 0x7f, /* control */
- };
- int i;
- int rc;
- int reserved;
-
- reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ);
- if (reserved != 0x07)
- return -ENODEV;
-
- rc = max6900_i2c_read_regs(client, regs);
- if (rc < 0)
- return rc;
-
- for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
- if (regs[i] & zero_mask[i])
- return -ENODEV;
- }
-
- return 0;
-}
-
static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
{
int rc;
@@ -202,7 +156,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
- BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
+ BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
return 0;
@@ -211,7 +165,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
static int max6900_i2c_clear_write_protect(struct i2c_client *client)
{
int rc;
- rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
+ rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0);
if (rc < 0) {
dev_err(&client->dev, "%s: control register write failed\n",
__func__);
@@ -220,8 +174,8 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client)
return 0;
}
-static int max6900_i2c_set_time(struct i2c_client *client,
- struct rtc_time const *tm)
+static int
+max6900_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
{
u8 regs[MAX6900_REG_LEN];
int rc;
@@ -258,89 +212,49 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
return max6900_i2c_set_time(to_i2c_client(dev), tm);
}
-static int max6900_attach_adapter(struct i2c_adapter *adapter)
-{
- return i2c_probe(adapter, &addr_data, max6900_probe);
-}
-
-static int max6900_detach_client(struct i2c_client *client)
+static int max6900_remove(struct i2c_client *client)
{
- struct rtc_device *const rtc = i2c_get_clientdata(client);
+ struct rtc_device *rtc = i2c_get_clientdata(client);
if (rtc)
rtc_device_unregister(rtc);
- return i2c_detach_client(client);
+ return 0;
}
-static struct i2c_driver max6900_driver = {
- .driver = {
- .name = DRV_NAME,
- },
- .id = I2C_DRIVERID_MAX6900,
- .attach_adapter = max6900_attach_adapter,
- .detach_client = max6900_detach_client,
-};
-
static const struct rtc_class_ops max6900_rtc_ops = {
- .read_time = max6900_rtc_read_time,
- .set_time = max6900_rtc_set_time,
+ .read_time = max6900_rtc_read_time,
+ .set_time = max6900_rtc_set_time,
};
-static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind)
+static int
+max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- int rc = 0;
- struct i2c_client *client = NULL;
- struct rtc_device *rtc = NULL;
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
- rc = -ENODEV;
- goto failout;
- }
-
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == NULL) {
- rc = -ENOMEM;
- goto failout;
- }
-
- client->addr = addr;
- client->adapter = adapter;
- client->driver = &max6900_driver;
- strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE);
-
- if (kind < 0) {
- rc = max6900_i2c_validate_client(client);
- if (rc < 0)
- goto failout;
- }
+ struct rtc_device *rtc;
- rc = i2c_attach_client(client);
- if (rc < 0)
- goto failout;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
- dev_info(&client->dev,
- "chip found, driver version " DRV_VERSION "\n");
+ dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(max6900_driver.driver.name,
- &client->dev,
- &max6900_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- rc = PTR_ERR(rtc);
- goto failout_detach;
- }
+ &client->dev, &max6900_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
return 0;
-
-failout_detach:
- i2c_detach_client(client);
-failout:
- kfree(client);
- return rc;
}
+static struct i2c_driver max6900_driver = {
+ .driver = {
+ .name = "rtc-max6900",
+ },
+ .probe = max6900_probe,
+ .remove = max6900_remove,
+};
+
static int __init max6900_init(void)
{
return i2c_add_driver(&max6900_driver);
@@ -352,6 +266,7 @@ static void __exit max6900_exit(void)
}
MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
+MODULE_AUTHOR("Dale Farnsworth <dale@farnsworth.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index 748a502a635..a829f20ad6d 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -179,58 +179,6 @@ struct pcf8563_limit
unsigned char max;
};
-static int pcf8563_validate_client(struct i2c_client *client)
-{
- int i;
-
- static const struct pcf8563_limit pattern[] = {
- /* register, mask, min, max */
- { PCF8563_REG_SC, 0x7F, 0, 59 },
- { PCF8563_REG_MN, 0x7F, 0, 59 },
- { PCF8563_REG_HR, 0x3F, 0, 23 },
- { PCF8563_REG_DM, 0x3F, 0, 31 },
- { PCF8563_REG_MO, 0x1F, 0, 12 },
- };
-
- /* check limits (only registers with bcd values) */
- for (i = 0; i < ARRAY_SIZE(pattern); i++) {
- int xfer;
- unsigned char value;
- unsigned char buf = pattern[i].reg;
-
- struct i2c_msg msgs[] = {
- { client->addr, 0, 1, &buf },
- { client->addr, I2C_M_RD, 1, &buf },
- };
-
- xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
-
- if (xfer != ARRAY_SIZE(msgs)) {
- dev_err(&client->dev,
- "%s: could not read register 0x%02X\n",
- __func__, pattern[i].reg);
-
- return -EIO;
- }
-
- value = BCD2BIN(buf & pattern[i].mask);
-
- if (value > pattern[i].max ||
- value < pattern[i].min) {
- dev_dbg(&client->dev,
- "%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
- "max=%d, value=%d, raw=0x%02X\n",
- __func__, i, pattern[i].reg, pattern[i].mask,
- pattern[i].min, pattern[i].max,
- value, buf);
-
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return pcf8563_get_datetime(to_i2c_client(dev), tm);
@@ -262,12 +210,6 @@ static int pcf8563_probe(struct i2c_client *client,
if (!pcf8563)
return -ENOMEM;
- /* Verify the chip is really an PCF8563 */
- if (pcf8563_validate_client(client) < 0) {
- err = -ENODEV;
- goto exit_kfree;
- }
-
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,
diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c
index 8448eeb9d67..82615355215 100644
--- a/drivers/rtc/rtc-pl030.c
+++ b/drivers/rtc/rtc-pl030.c
@@ -34,15 +34,6 @@ static irqreturn_t pl030_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int pl030_open(struct device *dev)
-{
- return 0;
-}
-
-static void pl030_release(struct device *dev)
-{
-}
-
static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
@@ -104,8 +95,6 @@ static int pl030_set_time(struct device *dev, struct rtc_time *tm)
}
static const struct rtc_class_ops pl030_ops = {
- .open = pl030_open,
- .release = pl030_release,
.ioctl = pl030_ioctl,
.read_time = pl030_read_time,
.set_time = pl030_set_time,
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index 08b4610ec5a..333eec689d2 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -45,18 +45,6 @@ static irqreturn_t pl031_interrupt(int irq, void *dev_id)
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);
@@ -118,8 +106,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
}
static const 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,
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 56caf6b2c3e..8b561958fb1 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -1,8 +1,9 @@
/*
- * An I2C driver for Ricoh RS5C372 and RV5C38[67] RTCs
+ * An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs
*
* Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
* Copyright (C) 2006 Tower Technologies
+ * Copyright (C) 2008 Paul Mundt
*
* 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
@@ -13,7 +14,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
-#define DRV_VERSION "0.5"
+#define DRV_VERSION "0.6"
/*
@@ -51,7 +52,8 @@
# define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */
#define RS5C_REG_CTRL2 15
# define RS5C372_CTRL2_24 (1 << 5)
-# define RS5C_CTRL2_XSTP (1 << 4)
+# define R2025_CTRL2_XST (1 << 5)
+# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2025S/D */
# define RS5C_CTRL2_CTFG (1 << 2)
# define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */
# define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */
@@ -63,6 +65,7 @@
enum rtc_type {
rtc_undef = 0,
+ rtc_r2025sd,
rtc_rs5c372a,
rtc_rs5c372b,
rtc_rv5c386,
@@ -70,6 +73,7 @@ enum rtc_type {
};
static const struct i2c_device_id rs5c372_id[] = {
+ { "r2025sd", rtc_r2025sd },
{ "rs5c372a", rtc_rs5c372a },
{ "rs5c372b", rtc_rs5c372b },
{ "rv5c386", rtc_rv5c386 },
@@ -89,6 +93,7 @@ struct rs5c372 {
enum rtc_type type;
unsigned time24:1;
unsigned has_irq:1;
+ unsigned smbus:1;
char buf[17];
char *regs;
};
@@ -106,10 +111,25 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
*
* The first method doesn't work with the iop3xx adapter driver, on at
* least 80219 chips; this works around that bug.
+ *
+ * The third method on the other hand doesn't work for the SMBus-only
+ * configurations, so we use the the first method there, stripping off
+ * the extra register in the process.
*/
- if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
- dev_warn(&client->dev, "can't read registers\n");
- return -EIO;
+ if (rs5c->smbus) {
+ int addr = RS5C_ADDR(RS5C372_REG_SECS);
+ int size = sizeof(rs5c->buf) - 1;
+
+ if (i2c_smbus_read_i2c_block_data(client, addr, size,
+ rs5c->buf + 1) != size) {
+ dev_warn(&client->dev, "can't read registers\n");
+ return -EIO;
+ }
+ } else {
+ if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
+ dev_warn(&client->dev, "can't read registers\n");
+ return -EIO;
+ }
}
dev_dbg(&client->dev,
@@ -187,6 +207,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct rs5c372 *rs5c = i2c_get_clientdata(client);
unsigned char buf[8];
+ int addr;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -194,16 +215,16 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
- buf[0] = RS5C_ADDR(RS5C372_REG_SECS);
- buf[1] = BIN2BCD(tm->tm_sec);
- buf[2] = BIN2BCD(tm->tm_min);
- buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour);
- buf[4] = BIN2BCD(tm->tm_wday);
- buf[5] = BIN2BCD(tm->tm_mday);
- buf[6] = BIN2BCD(tm->tm_mon + 1);
- buf[7] = BIN2BCD(tm->tm_year - 100);
+ addr = RS5C_ADDR(RS5C372_REG_SECS);
+ buf[0] = BIN2BCD(tm->tm_sec);
+ buf[1] = BIN2BCD(tm->tm_min);
+ buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
+ buf[3] = BIN2BCD(tm->tm_wday);
+ buf[4] = BIN2BCD(tm->tm_mday);
+ buf[5] = BIN2BCD(tm->tm_mon + 1);
+ buf[6] = BIN2BCD(tm->tm_year - 100);
- if ((i2c_master_send(client, buf, 8)) != 8) {
+ if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
}
@@ -266,16 +287,16 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client);
- unsigned char buf[2];
- int status;
+ unsigned char buf;
+ int status, addr;
- buf[1] = rs5c->regs[RS5C_REG_CTRL1];
+ buf = rs5c->regs[RS5C_REG_CTRL1];
switch (cmd) {
case RTC_UIE_OFF:
case RTC_UIE_ON:
/* some 327a modes use a different IRQ pin for 1Hz irqs */
if (rs5c->type == rtc_rs5c372a
- && (buf[1] & RS5C372A_CTRL1_SL1))
+ && (buf & RS5C372A_CTRL1_SL1))
return -ENOIOCTLCMD;
case RTC_AIE_OFF:
case RTC_AIE_ON:
@@ -293,28 +314,30 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
if (status < 0)
return status;
- buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
+ addr = RS5C_ADDR(RS5C_REG_CTRL1);
switch (cmd) {
case RTC_AIE_OFF: /* alarm off */
- buf[1] &= ~RS5C_CTRL1_AALE;
+ buf &= ~RS5C_CTRL1_AALE;
break;
case RTC_AIE_ON: /* alarm on */
- buf[1] |= RS5C_CTRL1_AALE;
+ buf |= RS5C_CTRL1_AALE;
break;
case RTC_UIE_OFF: /* update off */
- buf[1] &= ~RS5C_CTRL1_CT_MASK;
+ buf &= ~RS5C_CTRL1_CT_MASK;
break;
case RTC_UIE_ON: /* update on */
- buf[1] &= ~RS5C_CTRL1_CT_MASK;
- buf[1] |= RS5C_CTRL1_CT4;
+ buf &= ~RS5C_CTRL1_CT_MASK;
+ buf |= RS5C_CTRL1_CT4;
break;
}
- if ((i2c_master_send(client, buf, 2)) != 2) {
+
+ if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
printk(KERN_WARNING "%s: can't update alarm\n",
rs5c->rtc->name);
status = -EIO;
} else
- rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ rs5c->regs[RS5C_REG_CTRL1] = buf;
+
return status;
}
@@ -364,8 +387,8 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client);
- int status;
- unsigned char buf[4];
+ int status, addr, i;
+ unsigned char buf[3];
/* only handle up to 24 hours in the future, like RTC_ALM_SET */
if (t->time.tm_mday != -1
@@ -380,33 +403,36 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (status < 0)
return status;
if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
- buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
- buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
- if (i2c_master_send(client, buf, 2) != 2) {
+ addr = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
+ if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
return -EIO;
}
- rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
/* set alarm */
- buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN);
- buf[1] = BIN2BCD(t->time.tm_min);
- buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour);
- buf[3] = 0x7f; /* any/all days */
- if ((i2c_master_send(client, buf, 4)) != 4) {
- pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
- return -EIO;
+ buf[0] = BIN2BCD(t->time.tm_min);
+ buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
+ buf[2] = 0x7f; /* any/all days */
+
+ for (i = 0; i < sizeof(buf); i++) {
+ addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
+ if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
+ pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
+ return -EIO;
+ }
}
/* ... and maybe enable its irq */
if (t->enabled) {
- buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
- buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
- if ((i2c_master_send(client, buf, 2)) != 2)
+ addr = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
+ if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
printk(KERN_WARNING "%s: can't enable alarm\n",
rs5c->rtc->name);
- rs5c->regs[RS5C_REG_CTRL1] = buf[1];
+ rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
return 0;
@@ -503,18 +529,81 @@ static void rs5c_sysfs_unregister(struct device *dev)
static struct i2c_driver rs5c372_driver;
+static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
+{
+ unsigned char buf[2];
+ int addr, i, ret = 0;
+
+ if (rs5c372->type == rtc_r2025sd) {
+ if (!(rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST))
+ return ret;
+ rs5c372->regs[RS5C_REG_CTRL2] &= ~R2025_CTRL2_XST;
+ } else {
+ if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
+ return ret;
+ rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
+ }
+
+ addr = RS5C_ADDR(RS5C_REG_CTRL1);
+ buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
+ buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
+
+ /* use 24hr mode */
+ switch (rs5c372->type) {
+ case rtc_rs5c372a:
+ case rtc_rs5c372b:
+ buf[1] |= RS5C372_CTRL2_24;
+ rs5c372->time24 = 1;
+ break;
+ case rtc_r2025sd:
+ case rtc_rv5c386:
+ case rtc_rv5c387a:
+ buf[0] |= RV5C387_CTRL1_24;
+ rs5c372->time24 = 1;
+ break;
+ default:
+ /* impossible */
+ break;
+ }
+
+ for (i = 0; i < sizeof(buf); i++) {
+ addr = RS5C_ADDR(RS5C_REG_CTRL1 + i);
+ ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]);
+ if (unlikely(ret < 0))
+ return ret;
+ }
+
+ rs5c372->regs[RS5C_REG_CTRL1] = buf[0];
+ rs5c372->regs[RS5C_REG_CTRL2] = buf[1];
+
+ return 0;
+}
+
static int rs5c372_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err = 0;
+ int smbus_mode = 0;
struct rs5c372 *rs5c372;
struct rtc_time tm;
dev_dbg(&client->dev, "%s\n", __func__);
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto exit;
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ /*
+ * If we don't have any master mode adapter, try breaking
+ * it down in to the barest of capabilities.
+ */
+ if (i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ smbus_mode = 1;
+ else {
+ /* Still no good, give up */
+ err = -ENODEV;
+ goto exit;
+ }
}
if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
@@ -528,6 +617,7 @@ static int rs5c372_probe(struct i2c_client *client,
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs = &rs5c372->buf[1];
+ rs5c372->smbus = smbus_mode;
err = rs5c_get_regs(rs5c372);
if (err < 0)
@@ -543,6 +633,7 @@ static int rs5c372_probe(struct i2c_client *client,
if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
rs5c372->time24 = 1;
break;
+ case rtc_r2025sd:
case rtc_rv5c386:
case rtc_rv5c387a:
if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
@@ -558,39 +649,14 @@ static int rs5c372_probe(struct i2c_client *client,
/* if the oscillator lost power and no other software (like
* the bootloader) set it up, do it here.
+ *
+ * The R2025S/D does this a little differently than the other
+ * parts, so we special case that..
*/
- if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) {
- unsigned char buf[3];
-
- rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
-
- buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
- buf[1] = rs5c372->regs[RS5C_REG_CTRL1];
- buf[2] = rs5c372->regs[RS5C_REG_CTRL2];
-
- /* use 24hr mode */
- switch (rs5c372->type) {
- case rtc_rs5c372a:
- case rtc_rs5c372b:
- buf[2] |= RS5C372_CTRL2_24;
- rs5c372->time24 = 1;
- break;
- case rtc_rv5c386:
- case rtc_rv5c387a:
- buf[1] |= RV5C387_CTRL1_24;
- rs5c372->time24 = 1;
- break;
- default:
- /* impossible */
- break;
- }
-
- if ((i2c_master_send(client, buf, 3)) != 3) {
- dev_err(&client->dev, "setup error\n");
- goto exit_kfree;
- }
- rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
- rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
+ err = rs5c_oscillator_setup(rs5c372);
+ if (unlikely(err < 0)) {
+ dev_err(&client->dev, "setup error\n");
+ goto exit_kfree;
}
if (rs5c372_get_datetime(client, &tm) < 0)
@@ -598,6 +664,7 @@ static int rs5c372_probe(struct i2c_client *client,
dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",
({ char *s; switch (rs5c372->type) {
+ case rtc_r2025sd: s = "r2025sd"; break;
case rtc_rs5c372a: s = "rs5c372a"; break;
case rtc_rs5c372b: s = "rs5c372b"; break;
case rtc_rv5c386: s = "rv5c386"; break;
@@ -667,7 +734,8 @@ module_exit(rs5c372_exit);
MODULE_AUTHOR(
"Pavel Mironchik <pmironchik@optifacio.net>, "
- "Alessandro Zummo <a.zummo@towertech.it>");
+ "Alessandro Zummo <a.zummo@towertech.it>, "
+ "Paul Mundt <lethal@linux-sh.org>");
MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
index 1f88e9e914e..fcead4c4cd1 100644
--- a/drivers/rtc/rtc-sh.c
+++ b/drivers/rtc/rtc-sh.c
@@ -257,12 +257,6 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
spin_unlock_irq(&rtc->lock);
}
-static void sh_rtc_release(struct device *dev)
-{
- sh_rtc_setpie(dev, 0);
- sh_rtc_setaie(dev, 0);
-}
-
static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
@@ -559,7 +553,6 @@ static int sh_rtc_irq_set_freq(struct device *dev, int freq)
}
static struct rtc_class_ops sh_rtc_ops = {
- .release = sh_rtc_release,
.ioctl = sh_rtc_ioctl,
.read_time = sh_rtc_read_time,
.set_time = sh_rtc_set_time,
diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index 31d3c8c2858..9a7e920315f 100644
--- a/drivers/rtc/rtc-stk17ta8.c
+++ b/drivers/rtc/rtc-stk17ta8.c
@@ -215,17 +215,6 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void stk17ta8_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;
- stk17ta8_rtc_update_alarm(pdata);
- }
-}
-
static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
unsigned long arg)
{
@@ -254,7 +243,6 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
.set_time = stk17ta8_rtc_set_time,
.read_alarm = stk17ta8_rtc_read_alarm,
.set_alarm = stk17ta8_rtc_set_alarm,
- .release = stk17ta8_rtc_release,
.ioctl = stk17ta8_rtc_ioctl,
};
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 8f83fc994f5..f5e618562c5 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -2913,7 +2913,7 @@ claw_new_device(struct ccwgroup_device *cgdev)
if (ret != 0) {
printk(KERN_WARNING
"claw: ccw_device_set_online %s WRITE failed "
- "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev)
+ "with ret = %d\n", dev_name(&cgdev->cdev[WRITE]->dev),
ret);
goto out;
}
diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c
index cbe470493bf..19f5d5ed85e 100644
--- a/drivers/s390/net/ctcm_mpc.c
+++ b/drivers/s390/net/ctcm_mpc.c
@@ -1673,7 +1673,7 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo)
done:
if (rc) {
- ctcm_pr_info("ctcmpc : %s() failed\n", __FUNCTION__);
+ ctcm_pr_info("ctcmpc : %s() failed\n", __func__);
priv->xid->xid2_flag2 = 0x40;
grp->saved_xid2->xid2_flag2 = 0x40;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d3b211af4e1..403ecad48d4 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1640,6 +1640,7 @@ config ATARI_SCSI
tristate "Atari native SCSI support"
depends on ATARI && SCSI
select SCSI_SPI_ATTRS
+ select NVRAM
---help---
If you have an Atari with built-in NCR5380 SCSI controller (TT,
Falcon, ...) say Y to get it supported. Of course also, if you have
@@ -1670,14 +1671,6 @@ config ATARI_SCSI_RESET_BOOT
boot process fractionally longer but may assist recovery from errors
that leave the devices with SCSI operations partway completed.
-config TT_DMA_EMUL
- bool "Hades SCSI DMA emulator"
- depends on ATARI_SCSI && HADES
- help
- This option enables code which emulates the TT SCSI DMA chip on the
- Hades. This increases the SCSI transfer rates at least ten times
- compared to PIO transfers.
-
config MAC_SCSI
bool "Macintosh NCR5380 SCSI"
depends on MAC && SCSI=y
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
deleted file mode 100644
index cdc710ea00f..00000000000
--- a/drivers/scsi/atari_dma_emul.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
- *
- * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
- *
- * 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.
- *
- * This code was written using the Hades TOS source code as a
- * reference. This source code can be found on the home page
- * of Medusa Computer Systems.
- *
- * Version 0.1, 1997-09-24.
- *
- * This code should be considered experimental. It has only been
- * tested on a Hades with a 68060. It might not work on a Hades
- * with a 68040. Make backups of your hard drives before using
- * this code.
- */
-
-#include <linux/compiler.h>
-#include <asm/thread_info.h>
-#include <asm/uaccess.h>
-
-#define hades_dma_ctrl (*(unsigned char *) 0xffff8717)
-#define hades_psdm_reg (*(unsigned char *) 0xffff8741)
-
-#define TRANSFER_SIZE 16
-
-struct m68040_frame {
- unsigned long effaddr; /* effective address */
- unsigned short ssw; /* special status word */
- unsigned short wb3s; /* write back 3 status */
- unsigned short wb2s; /* write back 2 status */
- unsigned short wb1s; /* write back 1 status */
- unsigned long faddr; /* fault address */
- unsigned long wb3a; /* write back 3 address */
- unsigned long wb3d; /* write back 3 data */
- unsigned long wb2a; /* write back 2 address */
- unsigned long wb2d; /* write back 2 data */
- unsigned long wb1a; /* write back 1 address */
- unsigned long wb1dpd0; /* write back 1 data/push data 0*/
- unsigned long pd1; /* push data 1*/
- unsigned long pd2; /* push data 2*/
- unsigned long pd3; /* push data 3*/
-};
-
-static void writeback (unsigned short wbs, unsigned long wba,
- unsigned long wbd, void *old_buserr)
-{
- mm_segment_t fs = get_fs();
- static void *save_buserr;
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l %0,8(%%a0)\n\t"
- :
- : "r" (&&bus_error)
- : "a0" );
-
- save_buserr = old_buserr;
-
- set_fs (MAKE_MM_SEG(wbs & WBTM_040));
-
- switch (wbs & WBSIZ_040) {
- case BA_SIZE_BYTE:
- put_user (wbd & 0xff, (char *)wba);
- break;
- case BA_SIZE_WORD:
- put_user (wbd & 0xffff, (short *)wba);
- break;
- case BA_SIZE_LONG:
- put_user (wbd, (int *)wba);
- break;
- }
-
- set_fs (fs);
- return;
-
-bus_error:
- __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
- "bcs.s .jump_old\n\t"
- "cmp.l %1,2(%%sp)\n\t"
- "bls.s .restore_old\n"
- ".jump_old:\n\t"
- "move.l %2,-(%%sp)\n\t"
- "rts\n"
- ".restore_old:\n\t"
- "move.l %%a0,-(%%sp)\n\t"
- "movec.l %%vbr,%%a0\n\t"
- "move.l %2,8(%%a0)\n\t"
- "move.l (%%sp)+,%%a0\n\t"
- "rte\n\t"
- :
- : "i" (writeback), "i" (&&bus_error),
- "m" (save_buserr) );
-}
-
-/*
- * static inline void set_restdata_reg(unsigned char *cur_addr)
- *
- * Set the rest data register if necessary.
- */
-
-static inline void set_restdata_reg(unsigned char *cur_addr)
-{
- if (((long) cur_addr & ~3) != 0)
- tt_scsi_dma.dma_restdata =
- *((unsigned long *) ((long) cur_addr & ~3));
-}
-
-/*
- * void hades_dma_emulator(int irq, void *dummy)
- *
- * This code emulates TT SCSI DMA on the Hades.
- *
- * Note the following:
- *
- * 1. When there is no byte available to read from the SCSI bus, or
- * when a byte cannot yet bet written to the SCSI bus, a bus
- * error occurs when reading or writing the pseudo DMA data
- * register (hades_psdm_reg). We have to catch this bus error
- * and try again to read or write the byte. If after several tries
- * we still get a bus error, the interrupt handler is left. When
- * the byte can be read or written, the interrupt handler is
- * called again.
- *
- * 2. The SCSI interrupt must be disabled in this interrupt handler.
- *
- * 3. If we set the EOP signal, the SCSI controller still expects one
- * byte to be read or written. Therefore the last byte is transferred
- * separately, after setting the EOP signal.
- *
- * 4. When this function is left, the address pointer (start_addr) is
- * converted to a physical address. Because it points one byte
- * further than the last transferred byte, it can point outside the
- * current page. If virt_to_phys() is called with this address we
- * might get an access error. Therefore virt_to_phys() is called with
- * start_addr - 1 if the count has reached zero. The result is
- * increased with one.
- */
-
-static irqreturn_t hades_dma_emulator(int irq, void *dummy)
-{
- unsigned long dma_base;
- register unsigned long dma_cnt asm ("d3");
- static long save_buserr;
- register unsigned long save_sp asm ("d4");
- register int tries asm ("d5");
- register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
- register unsigned char *eff_addr;
- register unsigned char *psdm_reg;
- unsigned long rem;
-
- atari_disable_irq(IRQ_TT_MFP_SCSI);
-
- /*
- * Read the dma address and count registers.
- */
-
- dma_base = SCSI_DMA_READ_P(dma_addr);
- dma_cnt = SCSI_DMA_READ_P(dma_cnt);
-
- /*
- * Check if DMA is still enabled.
- */
-
- if ((tt_scsi_dma.dma_ctrl & 2) == 0)
- {
- atari_enable_irq(IRQ_TT_MFP_SCSI);
- return IRQ_HANDLED;
- }
-
- if (dma_cnt == 0)
- {
- printk(KERN_NOTICE "DMA emulation: count is zero.\n");
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
- atari_enable_irq(IRQ_TT_MFP_SCSI);
- return IRQ_HANDLED;
- }
-
- /*
- * Install new bus error routine.
- */
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l 8(%%a0),%0\n\t"
- "move.l %1,8(%%a0)\n\t"
- : "=&r" (save_buserr)
- : "r" (&&scsi_bus_error)
- : "a0" );
-
- hades_dma_ctrl &= 0xfc; /* Bus error and EOP off. */
-
- /*
- * Save the stack pointer.
- */
-
- __asm__ __volatile__ ("move.l %%sp,%0\n\t"
- : "=&r" (save_sp) );
-
- tries = 100; /* Maximum number of bus errors. */
- start_addr = phys_to_virt(dma_base);
- end_addr = start_addr + dma_cnt;
-
-scsi_loop:
- dma_cnt--;
- rem = dma_cnt & (TRANSFER_SIZE - 1);
- dma_cnt &= ~(TRANSFER_SIZE - 1);
- psdm_reg = &hades_psdm_reg;
-
- if (tt_scsi_dma.dma_ctrl & 1) /* Read or write? */
- {
- /*
- * SCSI write. Abort when count is zero.
- */
-
- switch (rem)
- {
- case 0:
- while (dma_cnt > 0)
- {
- dma_cnt -= TRANSFER_SIZE;
-
- *psdm_reg = *start_addr++;
- case 15:
- *psdm_reg = *start_addr++;
- case 14:
- *psdm_reg = *start_addr++;
- case 13:
- *psdm_reg = *start_addr++;
- case 12:
- *psdm_reg = *start_addr++;
- case 11:
- *psdm_reg = *start_addr++;
- case 10:
- *psdm_reg = *start_addr++;
- case 9:
- *psdm_reg = *start_addr++;
- case 8:
- *psdm_reg = *start_addr++;
- case 7:
- *psdm_reg = *start_addr++;
- case 6:
- *psdm_reg = *start_addr++;
- case 5:
- *psdm_reg = *start_addr++;
- case 4:
- *psdm_reg = *start_addr++;
- case 3:
- *psdm_reg = *start_addr++;
- case 2:
- *psdm_reg = *start_addr++;
- case 1:
- *psdm_reg = *start_addr++;
- }
- }
-
- hades_dma_ctrl |= 1; /* Set EOP. */
- udelay(10);
- *psdm_reg = *start_addr++; /* Dummy byte. */
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
- }
- else
- {
- /*
- * SCSI read. Abort when count is zero.
- */
-
- switch (rem)
- {
- case 0:
- while (dma_cnt > 0)
- {
- dma_cnt -= TRANSFER_SIZE;
-
- *start_addr++ = *psdm_reg;
- case 15:
- *start_addr++ = *psdm_reg;
- case 14:
- *start_addr++ = *psdm_reg;
- case 13:
- *start_addr++ = *psdm_reg;
- case 12:
- *start_addr++ = *psdm_reg;
- case 11:
- *start_addr++ = *psdm_reg;
- case 10:
- *start_addr++ = *psdm_reg;
- case 9:
- *start_addr++ = *psdm_reg;
- case 8:
- *start_addr++ = *psdm_reg;
- case 7:
- *start_addr++ = *psdm_reg;
- case 6:
- *start_addr++ = *psdm_reg;
- case 5:
- *start_addr++ = *psdm_reg;
- case 4:
- *start_addr++ = *psdm_reg;
- case 3:
- *start_addr++ = *psdm_reg;
- case 2:
- *start_addr++ = *psdm_reg;
- case 1:
- *start_addr++ = *psdm_reg;
- }
- }
-
- hades_dma_ctrl |= 1; /* Set EOP. */
- udelay(10);
- *start_addr++ = *psdm_reg;
- tt_scsi_dma.dma_ctrl &= 0xfd; /* DMA ready. */
-
- set_restdata_reg(start_addr);
- }
-
- if (start_addr != end_addr)
- printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
-
- dma_cnt = end_addr - start_addr;
-
-scsi_end:
- dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :
- virt_to_phys(start_addr);
-
- SCSI_DMA_WRITE_P(dma_addr, dma_base);
- SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
-
- /*
- * Restore old bus error routine.
- */
-
- __asm__ __volatile__ ("movec.l %%vbr,%%a0\n\t"
- "move.l %0,8(%%a0)\n\t"
- :
- : "r" (save_buserr)
- : "a0" );
-
- atari_enable_irq(IRQ_TT_MFP_SCSI);
-
- return IRQ_HANDLED;
-
-scsi_bus_error:
- /*
- * First check if the bus error is caused by our code.
- * If not, call the original handler.
- */
-
- __asm__ __volatile__ ("cmp.l %0,2(%%sp)\n\t"
- "bcs.s .old_vector\n\t"
- "cmp.l %1,2(%%sp)\n\t"
- "bls.s .scsi_buserr\n"
- ".old_vector:\n\t"
- "move.l %2,-(%%sp)\n\t"
- "rts\n"
- ".scsi_buserr:\n\t"
- :
- : "i" (&&scsi_loop), "i" (&&scsi_end),
- "m" (save_buserr) );
-
- if (CPU_IS_060)
- {
- /*
- * Get effective address and restore the stack.
- */
-
- __asm__ __volatile__ ("move.l 8(%%sp),%0\n\t"
- "move.l %1,%%sp\n\t"
- : "=a&" (eff_addr)
- : "r" (save_sp) );
- }
- else
- {
- register struct m68040_frame *frame;
-
- __asm__ __volatile__ ("lea 8(%%sp),%0\n\t"
- : "=a&" (frame) );
-
- if (tt_scsi_dma.dma_ctrl & 1)
- {
- /*
- * Bus error while writing.
- */
-
- if (frame->wb3s & WBV_040)
- {
- if (frame->wb3a == (long) &hades_psdm_reg)
- start_addr--;
- else
- writeback(frame->wb3s, frame->wb3a,
- frame->wb3d, &&scsi_bus_error);
- }
-
- if (frame->wb2s & WBV_040)
- {
- if (frame->wb2a == (long) &hades_psdm_reg)
- start_addr--;
- else
- writeback(frame->wb2s, frame->wb2a,
- frame->wb2d, &&scsi_bus_error);
- }
-
- if (frame->wb1s & WBV_040)
- {
- if (frame->wb1a == (long) &hades_psdm_reg)
- start_addr--;
- }
- }
- else
- {
- /*
- * Bus error while reading.
- */
-
- if (frame->wb3s & WBV_040)
- writeback(frame->wb3s, frame->wb3a,
- frame->wb3d, &&scsi_bus_error);
- }
-
- eff_addr = (unsigned char *) frame->faddr;
-
- __asm__ __volatile__ ("move.l %0,%%sp\n\t"
- :
- : "r" (save_sp) );
- }
-
- dma_cnt = end_addr - start_addr;
-
- if (eff_addr == &hades_psdm_reg)
- {
- /*
- * Bus error occurred while reading the pseudo
- * DMA register. Time out.
- */
-
- tries--;
-
- if (tries <= 0)
- {
- if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
- set_restdata_reg(start_addr);
-
- if (dma_cnt <= 1)
- printk(KERN_CRIT "DMA emulation: Fatal "
- "error while %s the last byte.\n",
- (tt_scsi_dma.dma_ctrl & 1)
- ? "writing" : "reading");
-
- goto scsi_end;
- }
- else
- goto scsi_loop;
- }
- else
- {
- /*
- * Bus error during pseudo DMA transfer.
- * Terminate the DMA transfer.
- */
-
- hades_dma_ctrl |= 3; /* Set EOP and bus error. */
- if ((tt_scsi_dma.dma_ctrl & 1) == 0) /* Read or write? */
- set_restdata_reg(start_addr);
- goto scsi_end;
- }
-}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index f5732d8f67f..21fe07f9df8 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -249,10 +249,6 @@ static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-#if defined(CONFIG_TT_DMA_EMUL)
-#include "atari_dma_emul.c"
-#endif
-
#if defined(REAL_DMA)
static int scsi_dma_is_ignored_buserr(unsigned char dma_stat)
@@ -695,21 +691,8 @@ int atari_scsi_detect(struct scsi_host_template *host)
#ifdef REAL_DMA
tt_scsi_dma.dma_ctrl = 0;
atari_dma_residual = 0;
-#ifdef CONFIG_TT_DMA_EMUL
- if (MACH_IS_HADES) {
- if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
- IRQ_TYPE_PRIO, "Hades DMA emulator",
- hades_dma_emulator)) {
- printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
- free_irq(IRQ_TT_MFP_SCSI, instance);
- scsi_unregister(atari_scsi_host);
- atari_stram_free(atari_dma_buffer);
- atari_dma_buffer = 0;
- return 0;
- }
- }
-#endif
- if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+
+ if (MACH_IS_MEDUSA) {
/* While the read overruns (described by Drew Eckhardt in
* NCR5380.c) never happened on TTs, they do in fact on the Medusa
* (This was the cause why SCSI didn't work right for so long
@@ -1007,11 +990,7 @@ static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
Scsi_Cmnd *cmd, int write_flag)
{
unsigned long possible_len, limit;
-#ifndef CONFIG_TT_DMA_EMUL
- if (MACH_IS_HADES)
- /* Hades has no SCSI DMA at all :-( Always force use of PIO */
- return 0;
-#endif
+
if (IS_A_TT())
/* TT SCSI DMA can transfer arbitrary #bytes */
return wanted_len;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index ec39203b879..1528de23a65 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2976,6 +2976,9 @@ static int __init serial8250_init(void)
"%d ports, IRQ sharing %sabled\n", nr_uarts,
share_irqs ? "en" : "dis");
+ for (i = 0; i < NR_IRQS; i++)
+ spin_lock_init(&irq_lists[i].lock);
+
#ifdef CONFIG_SPARC
ret = sunserial_register_minors(&serial8250_reg, UART_NR);
#else
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 31786b3b0a6..db783b77a88 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1123,42 +1123,6 @@ config SERIAL_CPM_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_CPM_SCC1
- bool "Support for SCC1 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SCC1 as a serial port
-
-config SERIAL_CPM_SCC2
- bool "Support for SCC2 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SCC2 as a serial port
-
-config SERIAL_CPM_SCC3
- bool "Support for SCC3 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SCC3 as a serial port
-
-config SERIAL_CPM_SCC4
- bool "Support for SCC4 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SCC4 as a serial port
-
-config SERIAL_CPM_SMC1
- bool "Support for SMC1 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SMC1 as a serial port
-
-config SERIAL_CPM_SMC2
- bool "Support for SMC2 serial port"
- depends on SERIAL_CPM=y
- help
- Select this option to use SMC2 as a serial port
-
config SERIAL_SGI_L1_CONSOLE
bool "SGI Altix L1 serial console support"
depends on IA64_GENERIC || IA64_SGI_SN2
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 25efca5a7a1..a6c4d744495 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -1333,6 +1333,9 @@ static int __devinit cpm_uart_probe(struct of_device *ofdev,
if (ret)
return ret;
+ /* initialize the device pointer for the port */
+ pinfo->port.dev = &ofdev->dev;
+
return uart_add_one_port(&cpm_reg, &pinfo->port);
}
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index 0f0aff06c59..1b94c56ec23 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -100,7 +100,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
mem_addr = (u8 *) cpm_dpram_addr(cpm_dpalloc(memsz, 8));
dma_addr = (u32)cpm_dpram_phys(mem_addr);
} else
- mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+ mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
GFP_KERNEL);
if (mem_addr == NULL) {
@@ -127,8 +127,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
- dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
- pinfo->rx_fifosize) +
+ dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+ pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), pinfo->mem_addr,
pinfo->dma_addr);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index b8db4d3eed3..141c0a3333a 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -136,7 +136,7 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
dma_addr = virt_to_bus(mem_addr);
}
else
- mem_addr = dma_alloc_coherent(NULL, memsz, &dma_addr,
+ mem_addr = dma_alloc_coherent(pinfo->port.dev, memsz, &dma_addr,
GFP_KERNEL);
if (mem_addr == NULL) {
@@ -163,8 +163,8 @@ int cpm_uart_allocbuf(struct uart_cpm_port *pinfo, unsigned int is_con)
void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
{
- dma_free_coherent(NULL, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
- pinfo->rx_fifosize) +
+ dma_free_coherent(pinfo->port.dev, L1_CACHE_ALIGN(pinfo->rx_nrfifos *
+ pinfo->rx_fifosize) +
L1_CACHE_ALIGN(pinfo->tx_nrfifos *
pinfo->tx_fifosize), (void __force *)pinfo->mem_addr,
pinfo->dma_addr);
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 36126070d9a..6117d3db0b6 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -72,13 +72,8 @@
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/io.h>
-
-#if defined(CONFIG_PPC_MERGE)
#include <linux/of.h>
#include <linux/of_platform.h>
-#else
-#include <linux/platform_device.h>
-#endif
#include <asm/mpc52xx.h>
#include <asm/mpc512x.h>
@@ -107,12 +102,11 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
* it's cleared, then a memset(...,0,...) should be added to
* the console_init
*/
-#if defined(CONFIG_PPC_MERGE)
+
/* lookup table for matching device nodes to index numbers */
static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
static void mpc52xx_uart_of_enumerate(void);
-#endif
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
@@ -255,17 +249,12 @@ static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
/* Search for bus-frequency property in this node or a parent */
static unsigned long mpc52xx_getuartclk(void *p)
{
-#if defined(CONFIG_PPC_MERGE)
/*
* 5200 UARTs have a / 32 prescaler
* but the generic serial code assumes 16
* so return ipb freq / 2
*/
return mpc52xx_find_ipb_freq(p) / 2;
-#else
- pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
- return NULL;
-#endif
}
static struct psc_ops mpc52xx_psc_ops = {
@@ -886,10 +875,6 @@ mpc52xx_console_get_options(struct uart_port *port,
/* CT{U,L}R are write-only ! */
*baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
-#if !defined(CONFIG_PPC_MERGE)
- if (__res.bi_baudrate)
- *baud = __res.bi_baudrate;
-#endif
/* Parse them */
switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
@@ -946,42 +931,6 @@ mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
psc_ops->cw_restore_ints(port);
}
-#if !defined(CONFIG_PPC_MERGE)
-static int __init
-mpc52xx_console_setup(struct console *co, char *options)
-{
- struct uart_port *port = &mpc52xx_uart_ports[co->index];
-
- int baud = CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (co->index < 0 || co->index >= MPC52xx_PSC_MAXNUM)
- return -EINVAL;
-
- /* Basic port init. Needed since we use some uart_??? func before
- * real init for early access */
- spin_lock_init(&port->lock);
- port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
- port->ops = &mpc52xx_uart_ops;
- port->mapbase = MPC52xx_PA(MPC52xx_PSCx_OFFSET(co->index+1));
-
- /* We ioremap ourself */
- port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
- if (port->membase == NULL)
- return -EINVAL;
-
- /* Setup the port parameters accoding to options */
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
- else
- mpc52xx_console_get_options(port, &baud, &parity, &bits, &flow);
-
- return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-#else
static int __init
mpc52xx_console_setup(struct console *co, char *options)
@@ -1053,7 +1002,6 @@ mpc52xx_console_setup(struct console *co, char *options)
return uart_set_options(port, co, baud, parity, bits, flow);
}
-#endif /* defined(CONFIG_PPC_MERGE) */
static struct uart_driver mpc52xx_uart_driver;
@@ -1072,9 +1020,7 @@ static struct console mpc52xx_console = {
static int __init
mpc52xx_console_init(void)
{
-#if defined(CONFIG_PPC_MERGE)
mpc52xx_uart_of_enumerate();
-#endif
register_console(&mpc52xx_console);
return 0;
}
@@ -1100,115 +1046,6 @@ static struct uart_driver mpc52xx_uart_driver = {
.cons = MPC52xx_PSC_CONSOLE,
};
-
-#if !defined(CONFIG_PPC_MERGE)
-/* ======================================================================== */
-/* Platform Driver */
-/* ======================================================================== */
-
-static int __devinit
-mpc52xx_uart_probe(struct platform_device *dev)
-{
- struct resource *res = dev->resource;
-
- struct uart_port *port = NULL;
- int i, idx, ret;
-
- /* Check validity & presence */
- idx = dev->id;
- if (idx < 0 || idx >= MPC52xx_PSC_MAXNUM)
- return -EINVAL;
-
- if (!mpc52xx_match_psc_function(idx, "uart"))
- return -ENODEV;
-
- /* Init the port structure */
- port = &mpc52xx_uart_ports[idx];
-
- spin_lock_init(&port->lock);
- port->uartclk = __res.bi_ipbfreq / 2; /* Look at CTLR doc */
- port->fifosize = 512;
- port->iotype = UPIO_MEM;
- port->flags = UPF_BOOT_AUTOCONF |
- (uart_console(port) ? 0 : UPF_IOREMAP);
- port->line = idx;
- port->ops = &mpc52xx_uart_ops;
- port->dev = &dev->dev;
-
- /* Search for IRQ and mapbase */
- for (i = 0 ; i < dev->num_resources ; i++, res++) {
- if (res->flags & IORESOURCE_MEM)
- port->mapbase = res->start;
- else if (res->flags & IORESOURCE_IRQ)
- port->irq = res->start;
- }
- if (!port->irq || !port->mapbase)
- return -EINVAL;
-
- /* Add the port to the uart sub-system */
- ret = uart_add_one_port(&mpc52xx_uart_driver, port);
- if (!ret)
- platform_set_drvdata(dev, (void *)port);
-
- return ret;
-}
-
-static int
-mpc52xx_uart_remove(struct platform_device *dev)
-{
- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
- platform_set_drvdata(dev, NULL);
-
- if (port)
- uart_remove_one_port(&mpc52xx_uart_driver, port);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int
-mpc52xx_uart_suspend(struct platform_device *dev, pm_message_t state)
-{
- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
- if (port)
- uart_suspend_port(&mpc52xx_uart_driver, port);
-
- return 0;
-}
-
-static int
-mpc52xx_uart_resume(struct platform_device *dev)
-{
- struct uart_port *port = (struct uart_port *) platform_get_drvdata(dev);
-
- if (port)
- uart_resume_port(&mpc52xx_uart_driver, port);
-
- return 0;
-}
-#endif
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpc52xx-psc");
-
-static struct platform_driver mpc52xx_uart_platform_driver = {
- .probe = mpc52xx_uart_probe,
- .remove = mpc52xx_uart_remove,
-#ifdef CONFIG_PM
- .suspend = mpc52xx_uart_suspend,
- .resume = mpc52xx_uart_resume,
-#endif
- .driver = {
- .owner = THIS_MODULE,
- .name = "mpc52xx-psc",
- },
-};
-#endif /* !defined(CONFIG_PPC_MERGE) */
-
-
-#if defined(CONFIG_PPC_MERGE)
/* ======================================================================== */
/* OF Platform Driver */
/* ======================================================================== */
@@ -1402,7 +1239,6 @@ static struct of_platform_driver mpc52xx_uart_of_driver = {
.name = "mpc52xx-psc-uart",
},
};
-#endif /* defined(CONFIG_PPC_MERGE) */
/* ======================================================================== */
@@ -1423,7 +1259,6 @@ mpc52xx_uart_init(void)
return ret;
}
-#if defined(CONFIG_PPC_MERGE)
mpc52xx_uart_of_enumerate();
ret = of_register_platform_driver(&mpc52xx_uart_of_driver);
@@ -1433,16 +1268,6 @@ mpc52xx_uart_init(void)
uart_unregister_driver(&mpc52xx_uart_driver);
return ret;
}
-#else
- psc_ops = &mpc52xx_psc_ops;
- ret = platform_driver_register(&mpc52xx_uart_platform_driver);
- if (ret) {
- printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
- __FILE__, ret);
- uart_unregister_driver(&mpc52xx_uart_driver);
- return ret;
- }
-#endif
return 0;
}
@@ -1450,11 +1275,7 @@ mpc52xx_uart_init(void)
static void __exit
mpc52xx_uart_exit(void)
{
-#if defined(CONFIG_PPC_MERGE)
of_unregister_platform_driver(&mpc52xx_uart_of_driver);
-#else
- platform_driver_unregister(&mpc52xx_uart_platform_driver);
-#endif
uart_unregister_driver(&mpc52xx_uart_driver);
}
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 5c5d18dcb6a..539c933b335 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -1009,7 +1009,7 @@ static int qe_uart_request_port(struct uart_port *port)
rx_size = L1_CACHE_ALIGN(qe_port->rx_nrfifos * qe_port->rx_fifosize);
tx_size = L1_CACHE_ALIGN(qe_port->tx_nrfifos * qe_port->tx_fifosize);
- bd_virt = dma_alloc_coherent(NULL, rx_size + tx_size, &bd_dma_addr,
+ bd_virt = dma_alloc_coherent(port->dev, rx_size + tx_size, &bd_dma_addr,
GFP_KERNEL);
if (!bd_virt) {
dev_err(port->dev, "could not allocate buffer descriptors\n");
@@ -1051,7 +1051,7 @@ static void qe_uart_release_port(struct uart_port *port)
container_of(port, struct uart_qe_port, port);
struct ucc_slow_private *uccs = qe_port->us_private;
- dma_free_coherent(NULL, qe_port->bd_size, qe_port->bd_virt,
+ dma_free_coherent(port->dev, qe_port->bd_size, qe_port->bd_virt,
qe_port->bd_dma_addr);
ucc_slow_free(uccs);
diff --git a/drivers/spi/mpc52xx_psc_spi.c b/drivers/spi/mpc52xx_psc_spi.c
index 25eda71f4bf..0debe11b67b 100644
--- a/drivers/spi/mpc52xx_psc_spi.c
+++ b/drivers/spi/mpc52xx_psc_spi.c
@@ -15,13 +15,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
-
-#if defined(CONFIG_PPC_MERGE)
#include <linux/of_platform.h>
-#else
-#include <linux/platform_device.h>
-#endif
-
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/io.h>
@@ -108,13 +102,13 @@ static void mpc52xx_psc_spi_activate_cs(struct spi_device *spi)
* Because psc->ccr is defined as 16bit register instead of 32bit
* just set the lower byte of BitClkDiv
*/
- ccr = in_be16(&psc->ccr);
+ ccr = in_be16((u16 __iomem *)&psc->ccr);
ccr &= 0xFF00;
if (cs->speed_hz)
ccr |= (MCLK / cs->speed_hz - 1) & 0xFF;
else /* by default SPI Clk 1MHz */
ccr |= (MCLK / 1000000 - 1) & 0xFF;
- out_be16(&psc->ccr, ccr);
+ out_be16((u16 __iomem *)&psc->ccr, ccr);
mps->bits_per_word = cs->bits_per_word;
if (mps->activate_cs)
@@ -347,7 +341,7 @@ static int mpc52xx_psc_spi_port_config(int psc_id, struct mpc52xx_psc_spi *mps)
/* Configure 8bit codec mode as a SPI master and use EOF flags */
/* SICR_SIM_CODEC8|SICR_GENCLK|SICR_SPI|SICR_MSTR|SICR_USEEOF */
out_be32(&psc->sicr, 0x0180C800);
- out_be16(&psc->ccr, 0x070F); /* by default SPI Clk 1MHz */
+ out_be16((u16 __iomem *)&psc->ccr, 0x070F); /* default SPI Clk 1MHz */
/* Set 2ms DTL delay */
out_8(&psc->ctur, 0x00);
@@ -471,53 +465,6 @@ static int __exit mpc52xx_psc_spi_do_remove(struct device *dev)
return 0;
}
-#if !defined(CONFIG_PPC_MERGE)
-static int __init mpc52xx_psc_spi_probe(struct platform_device *dev)
-{
- switch(dev->id) {
- case 1:
- case 2:
- case 3:
- case 6:
- return mpc52xx_psc_spi_do_probe(&dev->dev,
- MPC52xx_PA(MPC52xx_PSCx_OFFSET(dev->id)),
- MPC52xx_PSC_SIZE, platform_get_irq(dev, 0), dev->id);
- default:
- return -EINVAL;
- }
-}
-
-static int __exit mpc52xx_psc_spi_remove(struct platform_device *dev)
-{
- return mpc52xx_psc_spi_do_remove(&dev->dev);
-}
-
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:mpc52xx-psc-spi");
-
-static struct platform_driver mpc52xx_psc_spi_platform_driver = {
- .remove = __exit_p(mpc52xx_psc_spi_remove),
- .driver = {
- .name = "mpc52xx-psc-spi",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init mpc52xx_psc_spi_init(void)
-{
- return platform_driver_probe(&mpc52xx_psc_spi_platform_driver,
- mpc52xx_psc_spi_probe);
-}
-module_init(mpc52xx_psc_spi_init);
-
-static void __exit mpc52xx_psc_spi_exit(void)
-{
- platform_driver_unregister(&mpc52xx_psc_spi_platform_driver);
-}
-module_exit(mpc52xx_psc_spi_exit);
-
-#else /* defined(CONFIG_PPC_MERGE) */
-
static int __init mpc52xx_psc_spi_of_probe(struct of_device *op,
const struct of_device_id *match)
{
@@ -586,8 +533,6 @@ static void __exit mpc52xx_psc_spi_exit(void)
}
module_exit(mpc52xx_psc_spi_exit);
-#endif /* defined(CONFIG_PPC_MERGE) */
-
MODULE_AUTHOR("Dragos Carp");
MODULE_DESCRIPTION("MPC52xx PSC SPI Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/spi/orion_spi.c b/drivers/spi/orion_spi.c
index b872bfaf4bd..014becb7d53 100644
--- a/drivers/spi/orion_spi.c
+++ b/drivers/spi/orion_spi.c
@@ -364,6 +364,11 @@ static int orion_spi_setup(struct spi_device *spi)
return -EINVAL;
}
+ /* Fix ac timing if required. */
+ if (orion_spi->spi_info->enable_clock_fix)
+ orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG,
+ (1 << 14));
+
if (spi->bits_per_word == 0)
spi->bits_per_word = 8;
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index d47d3636227..dae87b1a4c6 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -47,6 +47,10 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define MAX_BUSES 3
+#define RX_THRESH_DFLT 8
+#define TX_THRESH_DFLT 8
+#define TIMOUT_DFLT 1000
+
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
#define RESET_DMA_CHANNEL (DCSR_NODESC | DMA_INT_MASK)
#define IS_DMA_ALIGNED(x) ((((u32)(x)) & 0x07) == 0)
@@ -1171,6 +1175,8 @@ static int setup(struct spi_device *spi)
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
struct ssp_device *ssp = drv_data->ssp;
unsigned int clk_div;
+ uint tx_thres = TX_THRESH_DFLT;
+ uint rx_thres = RX_THRESH_DFLT;
if (!spi->bits_per_word)
spi->bits_per_word = 8;
@@ -1209,8 +1215,7 @@ static int setup(struct spi_device *spi)
chip->cs_control = null_cs_control;
chip->enable_dma = 0;
- chip->timeout = 1000;
- chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
+ chip->timeout = TIMOUT_DFLT;
chip->dma_burst_size = drv_data->master_info->enable_dma ?
DCMD_BURST8 : 0;
}
@@ -1224,22 +1229,21 @@ static int setup(struct spi_device *spi)
if (chip_info) {
if (chip_info->cs_control)
chip->cs_control = chip_info->cs_control;
-
- chip->timeout = chip_info->timeout;
-
- chip->threshold = (SSCR1_RxTresh(chip_info->rx_threshold) &
- SSCR1_RFT) |
- (SSCR1_TxTresh(chip_info->tx_threshold) &
- SSCR1_TFT);
-
- chip->enable_dma = chip_info->dma_burst_size != 0
- && drv_data->master_info->enable_dma;
+ if (chip_info->timeout)
+ chip->timeout = chip_info->timeout;
+ if (chip_info->tx_threshold)
+ tx_thres = chip_info->tx_threshold;
+ if (chip_info->rx_threshold)
+ rx_thres = chip_info->rx_threshold;
+ chip->enable_dma = drv_data->master_info->enable_dma;
chip->dma_threshold = 0;
-
if (chip_info->enable_loopback)
chip->cr1 = SSCR1_LBM;
}
+ chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
+ (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
+
/* set dma burst and threshold outside of chip_info path so that if
* chip_info goes away after setting chip->enable_dma, the
* burst and threshold can still respond to changes in bits_per_word */
@@ -1268,17 +1272,19 @@ static int setup(struct spi_device *spi)
/* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP)
- dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
spi->bits_per_word,
clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- spi->mode & 0x3);
+ spi->mode & 0x3,
+ chip->enable_dma ? "DMA" : "PIO");
else
- dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d\n",
+ dev_dbg(&spi->dev, "%d bits/word, %ld Hz, mode %d, %s\n",
spi->bits_per_word,
- clk_get_rate(ssp->clk)
+ clk_get_rate(ssp->clk) / 2
/ (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
- spi->mode & 0x3);
+ spi->mode & 0x3,
+ chip->enable_dma ? "DMA" : "PIO");
if (spi->bits_per_word <= 8) {
chip->n_bytes = 1;
@@ -1407,9 +1413,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info;
struct spi_master *master;
- struct driver_data *drv_data = NULL;
+ struct driver_data *drv_data;
struct ssp_device *ssp;
- int status = 0;
+ int status;
platform_info = dev->platform_data;
@@ -1422,7 +1428,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
/* Allocate master with space for drv_data and null dma buffer */
master = spi_alloc_master(dev, sizeof(struct driver_data) + 16);
if (!master) {
- dev_err(&pdev->dev, "can not alloc spi_master\n");
+ dev_err(&pdev->dev, "cannot alloc spi_master\n");
ssp_free(ssp);
return -ENOMEM;
}
@@ -1458,7 +1464,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
status = request_irq(ssp->irq, ssp_int, 0, dev->bus_id, drv_data);
if (status < 0) {
- dev_err(&pdev->dev, "can not get IRQ\n");
+ dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
goto out_error_master_alloc;
}
@@ -1498,7 +1504,9 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
/* Load default SSP configuration */
write_SSCR0(0, drv_data->ioaddr);
- write_SSCR1(SSCR1_RxTresh(4) | SSCR1_TxTresh(12), drv_data->ioaddr);
+ write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
+ SSCR1_TxTresh(TX_THRESH_DFLT),
+ drv_data->ioaddr);
write_SSCR0(SSCR0_SerClkDiv(2)
| SSCR0_Motorola
| SSCR0_DataSize(8),
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 75e86865234..3734dc9708e 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -660,7 +660,7 @@ int spi_write_then_read(struct spi_device *spi,
int status;
struct spi_message message;
- struct spi_transfer x[2];
+ struct spi_transfer x;
u8 *local_buf;
/* Use preallocated DMA-safe buffer. We can't avoid copying here,
@@ -671,15 +671,9 @@ int spi_write_then_read(struct spi_device *spi,
return -EINVAL;
spi_message_init(&message);
- memset(x, 0, sizeof x);
- if (n_tx) {
- x[0].len = n_tx;
- spi_message_add_tail(&x[0], &message);
- }
- if (n_rx) {
- x[1].len = n_rx;
- spi_message_add_tail(&x[1], &message);
- }
+ memset(&x, 0, sizeof x);
+ x.len = n_tx + n_rx;
+ spi_message_add_tail(&x, &message);
/* ... unless someone else is using the pre-allocated buffer */
if (!mutex_trylock(&lock)) {
@@ -690,15 +684,15 @@ int spi_write_then_read(struct spi_device *spi,
local_buf = buf;
memcpy(local_buf, txbuf, n_tx);
- x[0].tx_buf = local_buf;
- x[1].rx_buf = local_buf + n_tx;
+ x.tx_buf = local_buf;
+ x.rx_buf = local_buf;
/* do the i/o */
status = spi_sync(spi, &message);
if (status == 0)
- memcpy(rxbuf, x[1].rx_buf, n_rx);
+ memcpy(rxbuf, x.rx_buf + n_tx, n_rx);
- if (x[0].tx_buf == buf)
+ if (x.tx_buf == buf)
mutex_unlock(&lock);
else
kfree(local_buf);
@@ -744,5 +738,5 @@ err0:
* driver registration) _could_ be dynamically linked (modular) ... costs
* include needing to have boardinfo data structures be much more public.
*/
-subsys_initcall(spi_init);
+postcore_initcall(spi_init);
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 3eb414b84a9..c252cbac00f 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -247,6 +247,9 @@ static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
writeb(0xff, hw->regs + S3C2410_SPPRE);
writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
+
+ if (hw->pdata && hw->pdata->gpio_setup)
+ hw->pdata->gpio_setup(hw->pdata, 1);
}
static int __init s3c24xx_spi_probe(struct platform_device *pdev)
@@ -412,6 +415,9 @@ static int s3c24xx_spi_suspend(struct platform_device *pdev, pm_message_t msg)
{
struct s3c24xx_spi *hw = platform_get_drvdata(pdev);
+ if (hw->pdata && hw->pdata->gpio_setup)
+ hw->pdata->gpio_setup(hw->pdata, 0);
+
clk_disable(hw->clk);
return 0;
}
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index ec7aeb502d1..41b6530b8f2 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -42,8 +42,6 @@
***************************************************************************/
/*
- * $Log: ixj.c,v $
- *
* Revision 4.8 2003/07/09 19:39:00 Daniele Bellucci
* Audit some copy_*_user and minor cleanup.
*
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index f79c2040758..0f13448c6f7 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -76,6 +76,14 @@ config FB_DDC
select I2C
default n
+config FB_BOOT_VESA_SUPPORT
+ bool
+ depends on FB
+ default n
+ ---help---
+ If true, at least one selected framebuffer driver can take advantage
+ of VESA video modes set at an early boot stage via the vga= parameter.
+
config FB_CFB_FILLRECT
tristate
depends on FB
@@ -254,16 +262,24 @@ config FB_PM2
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
- This is the frame buffer device driver for the Permedia2 AGP frame
- buffer card from ASK, aka `Graphic Blaster Exxtreme'. There is a
- product page at
- <http://www.ask.com.hk/product/Permedia%202/permedia2.htm>.
+ This is the frame buffer device driver for cards based on
+ the 3D Labs Permedia, Permedia 2 and Permedia 2V chips.
+ The driver was tested on the following cards:
+ Diamond FireGL 1000 PRO AGP
+ ELSA Gloria Synergy PCI
+ Appian Jeronimo PRO (both heads) PCI
+ 3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI
+ Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC
+ ASK Graphic Blaster Exxtreme AGP
+
+ To compile this driver as a module, choose M here: the
+ module will be called pm2fb.
config FB_PM2_FIFO_DISCONNECT
bool "enable FIFO disconnect feature"
depends on FB_PM2 && PCI
help
- Support the Permedia2 FIFO disconnect feature (see CONFIG_FB_PM2).
+ Support the Permedia2 FIFO disconnect feature.
config FB_ARMCLCD
tristate "ARM PrimeCell PL110 support"
@@ -673,6 +689,7 @@ config FB_VESA
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BOOT_VESA_SUPPORT
help
This is the frame buffer device driver for generic VESA 2.0
compliant graphic cards. The older VESA 1.2 cards are not supported.
@@ -681,23 +698,14 @@ config FB_VESA
config FB_EFI
bool "EFI-based Framebuffer Support"
- depends on (FB = y) && X86
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
- help
- This is the EFI frame buffer device driver. If the firmware on
- your platform is UEFI2.0, select Y to add support for
- Graphics Output Protocol for early console messages to appear.
-
-config FB_IMAC
- bool "Intel-based Macintosh Framebuffer Support"
depends on (FB = y) && X86 && EFI
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
- This is the frame buffer device driver for the Intel-based Macintosh
+ This is the EFI frame buffer device driver. If the firmware on
+ your platform is EFI 1.10 or UEFI 2.0, select Y to add support for
+ using the EFI framebuffer as your console.
config FB_N411
tristate "N411 Apollo/Hecuba devkit support"
@@ -1118,6 +1126,7 @@ config FB_INTEL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BOOT_VESA_SUPPORT
help
This driver supports the on-board graphics built in to the Intel
830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets.
@@ -1470,6 +1479,7 @@ config FB_SIS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select FB_BOOT_VESA_SUPPORT
help
This is the frame buffer device driver for the SiS 300, 315, 330
and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets.
@@ -1492,6 +1502,24 @@ config FB_SIS_315
(315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well
as XGI V3XT, V5, V8 and Z7.
+config FB_VIA
+ tristate "VIA UniChrome (Pro) and Chrome9 display support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_SOFT_CURSOR
+ select I2C_ALGOBIT
+ select I2C
+ help
+ This is the frame buffer device driver for Graphics chips of VIA
+ UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
+ CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896
+ /P4M900,VX800)
+ Say Y if you have a VIA UniChrome graphics board.
+
+ To compile this driver as a module, choose M here: the
+ module will be called viafb.
config FB_NEOMAGIC
tristate "NeoMagic display support"
depends on FB && PCI
@@ -1521,25 +1549,25 @@ config FB_KYRO
module will be called kyrofb.
config FB_3DFX
- tristate "3Dfx Banshee/Voodoo3 display support"
+ tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support"
depends on FB && PCI
select FB_CFB_IMAGEBLIT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
help
- This driver supports graphics boards with the 3Dfx Banshee/Voodoo3
- chips. Say Y if you have such a graphics board.
+ This driver supports graphics boards with the 3Dfx Banshee,
+ Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have
+ such a graphics board.
To compile this driver as a module, choose M here: the
module will be called tdfxfb.
config FB_3DFX_ACCEL
- bool "3Dfx Banshee/Voodoo3 Acceleration functions (EXPERIMENTAL)"
+ bool "3Dfx Acceleration functions (EXPERIMENTAL)"
depends on FB_3DFX && EXPERIMENTAL
---help---
- This will compile the 3Dfx Banshee/Voodoo3 frame buffer device
- with acceleration functions.
-
+ This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer
+ device driver with acceleration functions.
config FB_VOODOO1
tristate "3Dfx Voodoo Graphics (sst1) support"
@@ -1604,17 +1632,16 @@ config FB_TRIDENT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
- This driver is supposed to support graphics boards with the
- Trident CyberXXXX/Image/CyberBlade chips mostly found in laptops
+ This is the frame buffer device driver for Trident PCI/AGP chipsets.
+ Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D
+ and Blade XP.
+ There are also integrated versions of these chips called CyberXXXX,
+ CyberImage or CyberBlade. These chips are mostly found in laptops
but also on some motherboards. For more information, read
<file:Documentation/fb/tridentfb.txt>
- Cyberblade/i1 support will be removed soon, use the cyblafb driver
- instead.
-
Say Y if you have such a graphics board.
-
To compile this driver as a module, choose M here: the
module will be called tridentfb.
@@ -1869,6 +1896,28 @@ config FB_SH_MOBILE_LCDC
---help---
Frame buffer driver for the on-chip SH-Mobile LCD controller.
+config FB_TMIO
+ tristate "Toshiba Mobile IO FrameBuffer support"
+ depends on FB && MFD_CORE
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ ---help---
+ Frame buffer driver for the Toshiba Mobile IO integrated as found
+ on the Sharp SL-6000 series
+
+ This driver is also available as a module ( = code which can be
+ inserted and removed from the running kernel whenever you want). The
+ module will be called tmiofb. If you want to compile it as a module,
+ say M here and read <file:Documentation/kbuild/modules.txt>.
+
+ If unsure, say N.
+
+config FB_TMIO_ACCELL
+ bool "tmiofb acceleration"
+ depends on FB_TMIO
+ default y
+
config FB_S3C2410
tristate "S3C2410 LCD framebuffer support"
depends on FB && ARCH_S3C2410
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index ad0330bf9be..248bddc8d0b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_FB_ATY) += aty/ macmodes.o
obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o
obj-$(CONFIG_FB_RADEON) += aty/
obj-$(CONFIG_FB_SIS) += sis/
+obj-$(CONFIG_FB_VIA) += via/
obj-$(CONFIG_FB_KYRO) += kyro/
obj-$(CONFIG_FB_SAVAGE) += savage/
obj-$(CONFIG_FB_GEODE) += geode/
@@ -97,6 +98,7 @@ obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o
obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o
obj-$(CONFIG_FB_PXA) += pxafb.o
obj-$(CONFIG_FB_W100) += w100fb.o
+obj-$(CONFIG_FB_TMIO) += tmiofb.o
obj-$(CONFIG_FB_AU1100) += au1100fb.o
obj-$(CONFIG_FB_AU1200) += au1200fb.o
obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o
@@ -124,7 +126,6 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
obj-$(CONFIG_FB_VESA) += vesafb.o
-obj-$(CONFIG_FB_IMAC) += imacfb.o
obj-$(CONFIG_FB_EFI) += efifb.o
obj-$(CONFIG_FB_VGA16) += vga16fb.o
obj-$(CONFIG_FB_OF) += offb.o
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index d38fd521742..f8d0a57a07c 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -372,6 +372,13 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
var->transp.offset = var->transp.length = 0;
var->xoffset = var->yoffset = 0;
+ if (info->fix.smem_len) {
+ unsigned int smem_len = (var->xres_virtual * var->yres_virtual
+ * ((var->bits_per_pixel + 7) / 8));
+ if (smem_len > info->fix.smem_len)
+ return -EINVAL;
+ }
+
/* Saturate vertical and horizontal timings at maximum values */
var->vsync_len = min_t(u32, var->vsync_len,
(ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1);
diff --git a/drivers/video/aty/radeon_accel.c b/drivers/video/aty/radeon_accel.c
index aa95f835024..8718f7349d6 100644
--- a/drivers/video/aty/radeon_accel.c
+++ b/drivers/video/aty/radeon_accel.c
@@ -5,61 +5,61 @@
* --dte
*/
-static void radeon_fixup_offset(struct radeonfb_info *rinfo)
+#define FLUSH_CACHE_WORKAROUND 1
+
+void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries)
{
- u32 local_base;
-
- /* *** Ugly workaround *** */
- /*
- * On some platforms, the video memory is mapped at 0 in radeon chip space
- * (like PPCs) by the firmware. X will always move it up so that it's seen
- * by the chip to be at the same address as the PCI BAR.
- * That means that when switching back from X, there is a mismatch between
- * the offsets programmed into the engine. This means that potentially,
- * accel operations done before radeonfb has a chance to re-init the engine
- * will have incorrect offsets, and potentially trash system memory !
- *
- * The correct fix is for fbcon to never call any accel op before the engine
- * has properly been re-initialized (by a call to set_var), but this is a
- * complex fix. This workaround in the meantime, called before every accel
- * operation, makes sure the offsets are in sync.
- */
+ int i;
- radeon_fifo_wait (1);
- local_base = INREG(MC_FB_LOCATION) << 16;
- if (local_base == rinfo->fb_local_base)
- return;
+ for (i=0; i<2000000; i++) {
+ rinfo->fifo_free = INREG(RBBM_STATUS) & 0x7f;
+ if (rinfo->fifo_free >= entries)
+ return;
+ udelay(10);
+ }
+ printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
+ /* XXX Todo: attempt to reset the engine */
+}
- rinfo->fb_local_base = local_base;
+static inline void radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
+{
+ if (entries <= rinfo->fifo_free)
+ rinfo->fifo_free -= entries;
+ else
+ radeon_fifo_update_and_wait(rinfo, entries);
+}
- radeon_fifo_wait (3);
- OUTREG(DEFAULT_PITCH_OFFSET, (rinfo->pitch << 0x16) |
- (rinfo->fb_local_base >> 10));
- OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
- OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
+static inline void radeonfb_set_creg(struct radeonfb_info *rinfo, u32 reg,
+ u32 *cache, u32 new_val)
+{
+ if (new_val == *cache)
+ return;
+ *cache = new_val;
+ radeon_fifo_wait(rinfo, 1);
+ OUTREG(reg, new_val);
}
static void radeonfb_prim_fillrect(struct radeonfb_info *rinfo,
const struct fb_fillrect *region)
{
- radeon_fifo_wait(4);
-
- OUTREG(DP_GUI_MASTER_CNTL,
- rinfo->dp_gui_master_cntl /* contains, like GMC_DST_32BPP */
- | GMC_BRUSH_SOLID_COLOR
- | ROP3_P);
- if (radeon_get_dstbpp(rinfo->depth) != DST_8BPP)
- OUTREG(DP_BRUSH_FRGD_CLR, rinfo->pseudo_palette[region->color]);
- else
- OUTREG(DP_BRUSH_FRGD_CLR, region->color);
- OUTREG(DP_WRITE_MSK, 0xffffffff);
- OUTREG(DP_CNTL, (DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM));
-
- radeon_fifo_wait(2);
+ radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+ rinfo->dp_gui_mc_base | GMC_BRUSH_SOLID_COLOR | ROP3_P);
+ radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+ DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+ radeonfb_set_creg(rinfo, DP_BRUSH_FRGD_CLR, &rinfo->dp_brush_fg_cache,
+ region->color);
+
+ /* Ensure the dst cache is flushed and the engine idle before
+ * issuing the operation.
+ *
+ * This works around engine lockups on some cards
+ */
+#if FLUSH_CACHE_WORKAROUND
+ radeon_fifo_wait(rinfo, 2);
OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
-
- radeon_fifo_wait(2);
+#endif
+ radeon_fifo_wait(rinfo, 2);
OUTREG(DST_Y_X, (region->dy << 16) | region->dx);
OUTREG(DST_WIDTH_HEIGHT, (region->width << 16) | region->height);
}
@@ -70,15 +70,14 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
struct fb_fillrect modded;
int vxres, vyres;
- if (info->state != FBINFO_STATE_RUNNING)
+ WARN_ON(rinfo->gfx_mode);
+ if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
return;
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_fillrect(info, region);
return;
}
- radeon_fixup_offset(rinfo);
-
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
@@ -91,6 +90,10 @@ void radeonfb_fillrect(struct fb_info *info, const struct fb_fillrect *region)
if(modded.dx + modded.width > vxres) modded.width = vxres - modded.dx;
if(modded.dy + modded.height > vyres) modded.height = vyres - modded.dy;
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR )
+ modded.color = ((u32 *) (info->pseudo_palette))[region->color];
+
radeonfb_prim_fillrect(rinfo, &modded);
}
@@ -109,22 +112,22 @@ static void radeonfb_prim_copyarea(struct radeonfb_info *rinfo,
if ( xdir < 0 ) { sx += w-1; dx += w-1; }
if ( ydir < 0 ) { sy += h-1; dy += h-1; }
- radeon_fifo_wait(3);
- OUTREG(DP_GUI_MASTER_CNTL,
- rinfo->dp_gui_master_cntl /* i.e. GMC_DST_32BPP */
- | GMC_BRUSH_NONE
- | GMC_SRC_DSTCOLOR
- | ROP3_S
- | DP_SRC_SOURCE_MEMORY );
- OUTREG(DP_WRITE_MSK, 0xffffffff);
- OUTREG(DP_CNTL, (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0)
- | (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
-
- radeon_fifo_wait(2);
+ radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+ rinfo->dp_gui_mc_base |
+ GMC_BRUSH_NONE |
+ GMC_SRC_DATATYPE_COLOR |
+ ROP3_S |
+ DP_SRC_SOURCE_MEMORY);
+ radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+ (xdir>=0 ? DST_X_LEFT_TO_RIGHT : 0) |
+ (ydir>=0 ? DST_Y_TOP_TO_BOTTOM : 0));
+
+#if FLUSH_CACHE_WORKAROUND
+ radeon_fifo_wait(rinfo, 2);
OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
-
- radeon_fifo_wait(3);
+#endif
+ radeon_fifo_wait(rinfo, 3);
OUTREG(SRC_Y_X, (sy << 16) | sx);
OUTREG(DST_Y_X, (dy << 16) | dx);
OUTREG(DST_HEIGHT_WIDTH, (h << 16) | w);
@@ -143,15 +146,14 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
modded.width = area->width;
modded.height = area->height;
- if (info->state != FBINFO_STATE_RUNNING)
+ WARN_ON(rinfo->gfx_mode);
+ if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
return;
if (info->flags & FBINFO_HWACCEL_DISABLED) {
cfb_copyarea(info, area);
return;
}
- radeon_fixup_offset(rinfo);
-
vxres = info->var.xres_virtual;
vyres = info->var.yres_virtual;
@@ -168,13 +170,112 @@ void radeonfb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
radeonfb_prim_copyarea(rinfo, &modded);
}
+static void radeonfb_prim_imageblit(struct radeonfb_info *rinfo,
+ const struct fb_image *image,
+ u32 fg, u32 bg)
+{
+ unsigned int src_bytes, dwords;
+ u32 *bits;
+
+ radeonfb_set_creg(rinfo, DP_GUI_MASTER_CNTL, &rinfo->dp_gui_mc_cache,
+ rinfo->dp_gui_mc_base |
+ GMC_BRUSH_NONE |
+ GMC_SRC_DATATYPE_MONO_FG_BG |
+ ROP3_S |
+ GMC_BYTE_ORDER_MSB_TO_LSB |
+ DP_SRC_SOURCE_HOST_DATA);
+ radeonfb_set_creg(rinfo, DP_CNTL, &rinfo->dp_cntl_cache,
+ DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM);
+ radeonfb_set_creg(rinfo, DP_SRC_FRGD_CLR, &rinfo->dp_src_fg_cache, fg);
+ radeonfb_set_creg(rinfo, DP_SRC_BKGD_CLR, &rinfo->dp_src_bg_cache, bg);
+
+ radeon_fifo_wait(rinfo, 1);
+ OUTREG(DST_Y_X, (image->dy << 16) | image->dx);
+
+ /* Ensure the dst cache is flushed and the engine idle before
+ * issuing the operation.
+ *
+ * This works around engine lockups on some cards
+ */
+#if FLUSH_CACHE_WORKAROUND
+ radeon_fifo_wait(rinfo, 2);
+ OUTREG(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL);
+ OUTREG(WAIT_UNTIL, (WAIT_2D_IDLECLEAN | WAIT_DMA_GUI_IDLE));
+#endif
+
+ /* X here pads width to a multiple of 32 and uses the clipper to
+ * adjust the result. Is that really necessary ? Things seem to
+ * work ok for me without that and the doco doesn't seem to imply
+ * there is such a restriction.
+ */
+ OUTREG(DST_WIDTH_HEIGHT, (image->width << 16) | image->height);
+
+ src_bytes = (((image->width * image->depth) + 7) / 8) * image->height;
+ dwords = (src_bytes + 3) / 4;
+ bits = (u32*)(image->data);
+
+ while(dwords >= 8) {
+ radeon_fifo_wait(rinfo, 8);
+#if BITS_PER_LONG == 64
+ __raw_writeq(*((u64 *)(bits)), rinfo->mmio_base + HOST_DATA0);
+ __raw_writeq(*((u64 *)(bits+2)), rinfo->mmio_base + HOST_DATA2);
+ __raw_writeq(*((u64 *)(bits+4)), rinfo->mmio_base + HOST_DATA4);
+ __raw_writeq(*((u64 *)(bits+6)), rinfo->mmio_base + HOST_DATA6);
+ bits += 8;
+#else
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA1);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA2);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA3);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA4);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA5);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA6);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA7);
+#endif
+ dwords -= 8;
+ }
+ while(dwords--) {
+ radeon_fifo_wait(rinfo, 1);
+ __raw_writel(*(bits++), rinfo->mmio_base + HOST_DATA0);
+ }
+}
+
void radeonfb_imageblit(struct fb_info *info, const struct fb_image *image)
{
struct radeonfb_info *rinfo = info->par;
+ u32 fg, bg;
- if (info->state != FBINFO_STATE_RUNNING)
+ WARN_ON(rinfo->gfx_mode);
+ if (info->state != FBINFO_STATE_RUNNING || rinfo->gfx_mode)
+ return;
+
+ if (!image->width || !image->height)
return;
- radeon_engine_idle();
+
+ /* We only do 1 bpp color expansion for now */
+ if (info->flags & FBINFO_HWACCEL_DISABLED || image->depth != 1)
+ goto fallback;
+
+ /* Fallback if running out of the screen. We may do clipping
+ * in the future */
+ if ((image->dx + image->width) > info->var.xres_virtual ||
+ (image->dy + image->height) > info->var.yres_virtual)
+ goto fallback;
+
+ if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
+ fg = ((u32*)(info->pseudo_palette))[image->fg_color];
+ bg = ((u32*)(info->pseudo_palette))[image->bg_color];
+ } else {
+ fg = image->fg_color;
+ bg = image->bg_color;
+ }
+
+ radeonfb_prim_imageblit(rinfo, image, fg, bg);
+ return;
+
+ fallback:
+ radeon_engine_idle(rinfo);
cfb_imageblit(info, image);
}
@@ -185,7 +286,8 @@ int radeonfb_sync(struct fb_info *info)
if (info->state != FBINFO_STATE_RUNNING)
return 0;
- radeon_engine_idle();
+
+ radeon_engine_idle(rinfo);
return 0;
}
@@ -211,9 +313,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
host_path_cntl = INREG(HOST_PATH_CNTL);
rbbm_soft_reset = INREG(RBBM_SOFT_RESET);
- if (rinfo->family == CHIP_FAMILY_R300 ||
- rinfo->family == CHIP_FAMILY_R350 ||
- rinfo->family == CHIP_FAMILY_RV350) {
+ if (IS_R300_VARIANT(rinfo)) {
u32 tmp;
OUTREG(RBBM_SOFT_RESET, (rbbm_soft_reset |
@@ -249,9 +349,7 @@ void radeonfb_engine_reset(struct radeonfb_info *rinfo)
INREG(HOST_PATH_CNTL);
OUTREG(HOST_PATH_CNTL, host_path_cntl);
- if (rinfo->family != CHIP_FAMILY_R300 &&
- rinfo->family != CHIP_FAMILY_R350 &&
- rinfo->family != CHIP_FAMILY_RV350)
+ if (!IS_R300_VARIANT(rinfo))
OUTREG(RBBM_SOFT_RESET, rbbm_soft_reset);
OUTREG(CLOCK_CNTL_INDEX, clock_cntl_index);
@@ -265,15 +363,24 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo)
/* disable 3D engine */
OUTREG(RB3D_CNTL, 0);
+ rinfo->fifo_free = 0;
radeonfb_engine_reset(rinfo);
- radeon_fifo_wait (1);
- if ((rinfo->family != CHIP_FAMILY_R300) &&
- (rinfo->family != CHIP_FAMILY_R350) &&
- (rinfo->family != CHIP_FAMILY_RV350))
+ radeon_fifo_wait(rinfo, 1);
+ if (IS_R300_VARIANT(rinfo)) {
+ OUTREG(RB2D_DSTCACHE_MODE, INREG(RB2D_DSTCACHE_MODE) |
+ RB2D_DC_AUTOFLUSH_ENABLE |
+ RB2D_DC_DC_DISABLE_IGNORE_PE);
+ } else {
+ /* This needs to be double checked with ATI. Latest X driver
+ * completely "forgets" to set this register on < r3xx, and
+ * we used to just write 0 there... I'll keep the 0 and update
+ * that when we have sorted things out on X side.
+ */
OUTREG(RB2D_DSTCACHE_MODE, 0);
+ }
- radeon_fifo_wait (3);
+ radeon_fifo_wait(rinfo, 3);
/* We re-read MC_FB_LOCATION from card as it can have been
* modified by XFree drivers (ouch !)
*/
@@ -284,41 +391,57 @@ void radeonfb_engine_init (struct radeonfb_info *rinfo)
OUTREG(DST_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
OUTREG(SRC_PITCH_OFFSET, (rinfo->pitch << 0x16) | (rinfo->fb_local_base >> 10));
- radeon_fifo_wait (1);
-#if defined(__BIG_ENDIAN)
+ radeon_fifo_wait(rinfo, 1);
+#ifdef __BIG_ENDIAN
OUTREGP(DP_DATATYPE, HOST_BIG_ENDIAN_EN, ~HOST_BIG_ENDIAN_EN);
#else
OUTREGP(DP_DATATYPE, 0, ~HOST_BIG_ENDIAN_EN);
#endif
- radeon_fifo_wait (2);
+ radeon_fifo_wait(rinfo, 2);
OUTREG(DEFAULT_SC_TOP_LEFT, 0);
OUTREG(DEFAULT_SC_BOTTOM_RIGHT, (DEFAULT_SC_RIGHT_MAX |
DEFAULT_SC_BOTTOM_MAX));
+ /* set default DP_GUI_MASTER_CNTL */
temp = radeon_get_dstbpp(rinfo->depth);
- rinfo->dp_gui_master_cntl = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
+ rinfo->dp_gui_mc_base = ((temp << 8) | GMC_CLR_CMP_CNTL_DIS);
- radeon_fifo_wait (1);
- OUTREG(DP_GUI_MASTER_CNTL, (rinfo->dp_gui_master_cntl |
- GMC_BRUSH_SOLID_COLOR |
- GMC_SRC_DATATYPE_COLOR));
+ rinfo->dp_gui_mc_cache = rinfo->dp_gui_mc_base |
+ GMC_BRUSH_SOLID_COLOR |
+ GMC_SRC_DATATYPE_COLOR;
+ radeon_fifo_wait(rinfo, 1);
+ OUTREG(DP_GUI_MASTER_CNTL, rinfo->dp_gui_mc_cache);
- radeon_fifo_wait (7);
/* clear line drawing regs */
+ radeon_fifo_wait(rinfo, 2);
OUTREG(DST_LINE_START, 0);
OUTREG(DST_LINE_END, 0);
- /* set brush color regs */
- OUTREG(DP_BRUSH_FRGD_CLR, 0xffffffff);
- OUTREG(DP_BRUSH_BKGD_CLR, 0x00000000);
-
- /* set source color regs */
- OUTREG(DP_SRC_FRGD_CLR, 0xffffffff);
- OUTREG(DP_SRC_BKGD_CLR, 0x00000000);
+ /* set brush and source color regs */
+ rinfo->dp_brush_fg_cache = 0xffffffff;
+ rinfo->dp_brush_bg_cache = 0x00000000;
+ rinfo->dp_src_fg_cache = 0xffffffff;
+ rinfo->dp_src_bg_cache = 0x00000000;
+ radeon_fifo_wait(rinfo, 4);
+ OUTREG(DP_BRUSH_FRGD_CLR, rinfo->dp_brush_fg_cache);
+ OUTREG(DP_BRUSH_BKGD_CLR, rinfo->dp_brush_bg_cache);
+ OUTREG(DP_SRC_FRGD_CLR, rinfo->dp_src_fg_cache);
+ OUTREG(DP_SRC_BKGD_CLR, rinfo->dp_src_bg_cache);
+
+ /* Default direction */
+ rinfo->dp_cntl_cache = DST_X_LEFT_TO_RIGHT | DST_Y_TOP_TO_BOTTOM;
+ radeon_fifo_wait(rinfo, 1);
+ OUTREG(DP_CNTL, rinfo->dp_cntl_cache);
/* default write mask */
+ radeon_fifo_wait(rinfo, 1);
OUTREG(DP_WRITE_MSK, 0xffffffff);
- radeon_engine_idle ();
+ /* Default to no swapping of host data */
+ radeon_fifo_wait(rinfo, 1);
+ OUTREG(RBBM_GUICNTL, RBBM_GUICNTL_HOST_DATA_SWAP_NONE);
+
+ /* Make sure it's settled */
+ radeon_engine_idle(rinfo);
}
diff --git a/drivers/video/aty/radeon_backlight.c b/drivers/video/aty/radeon_backlight.c
index 1a056adb61c..f343ba83f0a 100644
--- a/drivers/video/aty/radeon_backlight.c
+++ b/drivers/video/aty/radeon_backlight.c
@@ -66,7 +66,7 @@ static int radeon_bl_update_status(struct backlight_device *bd)
level = bd->props.brightness;
del_timer_sync(&rinfo->lvds_timer);
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
lvds_gen_cntl = INREG(LVDS_GEN_CNTL);
if (level > 0) {
diff --git a/drivers/video/aty/radeon_base.c b/drivers/video/aty/radeon_base.c
index 652273e9f5f..9a5821c65eb 100644
--- a/drivers/video/aty/radeon_base.c
+++ b/drivers/video/aty/radeon_base.c
@@ -852,7 +852,6 @@ static int radeonfb_pan_display (struct fb_var_screeninfo *var,
if (rinfo->asleep)
return 0;
- radeon_fifo_wait(2);
OUTREG(CRTC_OFFSET, ((var->yoffset * var->xres_virtual + var->xoffset)
* var->bits_per_pixel / 8) & ~7);
return 0;
@@ -882,7 +881,6 @@ static int radeonfb_ioctl (struct fb_info *info, unsigned int cmd,
if (rc)
return rc;
- radeon_fifo_wait(2);
if (value & 0x01) {
tmp = INREG(LVDS_GEN_CNTL);
@@ -940,7 +938,7 @@ int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch)
if (rinfo->lock_blank)
return 0;
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
val = INREG(CRTC_EXT_CNTL);
val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS |
@@ -1048,7 +1046,7 @@ static int radeonfb_blank (int blank, struct fb_info *info)
if (rinfo->asleep)
return 0;
-
+
return radeon_screen_blank(rinfo, blank, 0);
}
@@ -1074,8 +1072,6 @@ static int radeon_setcolreg (unsigned regno, unsigned red, unsigned green,
pindex = regno;
if (!rinfo->asleep) {
- radeon_fifo_wait(9);
-
if (rinfo->bpp == 16) {
pindex = regno * 8;
@@ -1244,8 +1240,6 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
{
int i;
- radeon_fifo_wait(20);
-
/* Workaround from XFree */
if (rinfo->is_mobility) {
/* A temporal workaround for the occational blanking on certain laptop
@@ -1286,11 +1280,10 @@ static void radeon_write_pll_regs(struct radeonfb_info *rinfo, struct radeon_reg
radeon_pll_errata_after_data(rinfo);
/* Set PPLL ref. div */
- if (rinfo->family == CHIP_FAMILY_R300 ||
+ if (IS_R300_VARIANT(rinfo) ||
rinfo->family == CHIP_FAMILY_RS300 ||
- rinfo->family == CHIP_FAMILY_R350 ||
- rinfo->family == CHIP_FAMILY_RV350 ||
- rinfo->family == CHIP_FAMILY_RV380 ) {
+ rinfo->family == CHIP_FAMILY_RS400 ||
+ rinfo->family == CHIP_FAMILY_RS480) {
if (mode->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting.
@@ -1342,7 +1335,7 @@ static void radeon_lvds_timer_func(unsigned long data)
{
struct radeonfb_info *rinfo = (struct radeonfb_info *)data;
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
OUTREG(LVDS_GEN_CNTL, rinfo->pending_lvds_gen_cntl);
}
@@ -1360,10 +1353,11 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
if (nomodeset)
return;
+ radeon_engine_idle(rinfo);
+
if (!regs_only)
radeon_screen_blank(rinfo, FB_BLANK_NORMAL, 0);
- radeon_fifo_wait(31);
for (i=0; i<10; i++)
OUTREG(common_regs[i].reg, common_regs[i].val);
@@ -1391,7 +1385,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
radeon_write_pll_regs(rinfo, mode);
if ((primary_mon == MT_DFP) || (primary_mon == MT_LCD)) {
- radeon_fifo_wait(10);
OUTREG(FP_CRTC_H_TOTAL_DISP, mode->fp_crtc_h_total_disp);
OUTREG(FP_CRTC_V_TOTAL_DISP, mode->fp_crtc_v_total_disp);
OUTREG(FP_H_SYNC_STRT_WID, mode->fp_h_sync_strt_wid);
@@ -1406,7 +1399,6 @@ void radeon_write_mode (struct radeonfb_info *rinfo, struct radeon_regs *mode,
if (!regs_only)
radeon_screen_blank(rinfo, FB_BLANK_UNBLANK, 0);
- radeon_fifo_wait(2);
OUTPLL(VCLK_ECP_CNTL, mode->vclk_ecp_cntl);
return;
@@ -1461,10 +1453,7 @@ static void radeon_calc_pll_regs(struct radeonfb_info *rinfo, struct radeon_regs
/* Not all chip revs have the same format for this register,
* extract the source selection
*/
- if (rinfo->family == CHIP_FAMILY_R200 ||
- rinfo->family == CHIP_FAMILY_R300 ||
- rinfo->family == CHIP_FAMILY_R350 ||
- rinfo->family == CHIP_FAMILY_RV350) {
+ if (rinfo->family == CHIP_FAMILY_R200 || IS_R300_VARIANT(rinfo)) {
source = (fp2_gen_cntl >> 10) & 0x3;
/* sourced from transform unit, check for transform unit
* own source
@@ -1560,7 +1549,7 @@ static int radeonfb_set_par(struct fb_info *info)
/* We always want engine to be idle on a mode switch, even
* if we won't actually change the mode
*/
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
hSyncStart = mode->xres + mode->right_margin;
hSyncEnd = hSyncStart + mode->hsync_len;
@@ -1855,7 +1844,6 @@ static int radeonfb_set_par(struct fb_info *info)
return 0;
}
-
static struct fb_ops radeonfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = radeonfb_check_var,
@@ -1879,6 +1867,7 @@ static int __devinit radeon_set_fbinfo (struct radeonfb_info *rinfo)
info->par = rinfo;
info->pseudo_palette = rinfo->pseudo_palette;
info->flags = FBINFO_DEFAULT
+ | FBINFO_HWACCEL_IMAGEBLIT
| FBINFO_HWACCEL_COPYAREA
| FBINFO_HWACCEL_FILLRECT
| FBINFO_HWACCEL_XPAN
@@ -2005,11 +1994,11 @@ static void radeon_identify_vram(struct radeonfb_info *rinfo)
(rinfo->family == CHIP_FAMILY_RS200) ||
(rinfo->family == CHIP_FAMILY_RS300) ||
(rinfo->family == CHIP_FAMILY_RC410) ||
+ (rinfo->family == CHIP_FAMILY_RS400) ||
(rinfo->family == CHIP_FAMILY_RS480) ) {
u32 tom = INREG(NB_TOM);
tmp = ((((tom >> 16) - (tom & 0xffff) + 1) << 6) * 1024);
- radeon_fifo_wait(6);
OUTREG(MC_FB_LOCATION, tom);
OUTREG(DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
OUTREG(CRTC2_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 8c8fa35f1b7..2c5567175dc 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -139,12 +139,8 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
u8 **out_edid)
{
- u32 reg = rinfo->i2c[conn-1].ddc_reg;
u8 *edid;
- OUTREG(reg, INREG(reg) &
- ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
-
edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
if (out_edid)
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 675abdafc2d..3df5015f1d1 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -2653,9 +2653,9 @@ int radeonfb_pci_suspend(struct pci_dev *pdev, pm_message_t mesg)
if (!(info->flags & FBINFO_HWACCEL_DISABLED)) {
/* Make sure engine is reset */
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
radeonfb_engine_reset(rinfo);
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
}
/* Blank display and LCD */
@@ -2767,7 +2767,7 @@ int radeonfb_pci_resume(struct pci_dev *pdev)
rinfo->asleep = 0;
} else
- radeon_engine_idle();
+ radeon_engine_idle(rinfo);
/* Restore display & engine */
radeon_write_mode (rinfo, &rinfo->state, 1);
diff --git a/drivers/video/aty/radeonfb.h b/drivers/video/aty/radeonfb.h
index ccbfffd1280..ea0b5b47aca 100644
--- a/drivers/video/aty/radeonfb.h
+++ b/drivers/video/aty/radeonfb.h
@@ -53,6 +53,7 @@ enum radeon_family {
CHIP_FAMILY_RV380, /* RV370/RV380/M22/M24 */
CHIP_FAMILY_R420, /* R420/R423/M18 */
CHIP_FAMILY_RC410,
+ CHIP_FAMILY_RS400,
CHIP_FAMILY_RS480,
CHIP_FAMILY_LAST,
};
@@ -335,7 +336,15 @@ struct radeonfb_info {
int mon2_type;
u8 *mon2_EDID;
- u32 dp_gui_master_cntl;
+ /* accel bits */
+ u32 dp_gui_mc_base;
+ u32 dp_gui_mc_cache;
+ u32 dp_cntl_cache;
+ u32 dp_brush_fg_cache;
+ u32 dp_brush_bg_cache;
+ u32 dp_src_fg_cache;
+ u32 dp_src_bg_cache;
+ u32 fifo_free;
struct pll_info pll;
@@ -347,6 +356,7 @@ struct radeonfb_info {
int lock_blank;
int dynclk;
int no_schedule;
+ int gfx_mode;
enum radeon_pm_mode pm_mode;
reinit_function_ptr reinit_func;
@@ -391,8 +401,14 @@ static inline void _radeon_msleep(struct radeonfb_info *rinfo, unsigned long ms)
#define OUTREG8(addr,val) writeb(val, (rinfo->mmio_base)+addr)
#define INREG16(addr) readw((rinfo->mmio_base)+addr)
#define OUTREG16(addr,val) writew(val, (rinfo->mmio_base)+addr)
+
+#ifdef CONFIG_PPC
+#define INREG(addr) ({ eieio(); ld_le32(rinfo->mmio_base+(addr)); })
+#define OUTREG(addr,val) do { eieio(); st_le32(rinfo->mmio_base+(addr),(val)); } while(0)
+#else
#define INREG(addr) readl((rinfo->mmio_base)+addr)
#define OUTREG(addr,val) writel(val, (rinfo->mmio_base)+addr)
+#endif
static inline void _OUTREGP(struct radeonfb_info *rinfo, u32 addr,
u32 val, u32 mask)
@@ -533,16 +549,25 @@ static inline u32 radeon_get_dstbpp(u16 depth)
/*
* 2D Engine helper routines
*/
+
+extern void radeon_fifo_update_and_wait(struct radeonfb_info *rinfo, int entries);
+
static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
{
int i;
- /* initiate flush */
- OUTREGP(RB2D_DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
+ /* Initiate flush */
+ OUTREGP(DSTCACHE_CTLSTAT, RB2D_DC_FLUSH_ALL,
~RB2D_DC_FLUSH_ALL);
+ /* Ensure FIFO is empty, ie, make sure the flush commands
+ * has reached the cache
+ */
+ radeon_fifo_update_and_wait(rinfo, 64);
+
+ /* Wait for the flush to complete */
for (i=0; i < 2000000; i++) {
- if (!(INREG(RB2D_DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
+ if (!(INREG(DSTCACHE_CTLSTAT) & RB2D_DC_BUSY))
return;
udelay(1);
}
@@ -550,25 +575,12 @@ static inline void radeon_engine_flush (struct radeonfb_info *rinfo)
}
-static inline void _radeon_fifo_wait(struct radeonfb_info *rinfo, int entries)
-{
- int i;
-
- for (i=0; i<2000000; i++) {
- if ((INREG(RBBM_STATUS) & 0x7f) >= entries)
- return;
- udelay(1);
- }
- printk(KERN_ERR "radeonfb: FIFO Timeout !\n");
-}
-
-
-static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
+static inline void radeon_engine_idle(struct radeonfb_info *rinfo)
{
int i;
/* ensure FIFO is empty before waiting for idle */
- _radeon_fifo_wait (rinfo, 64);
+ radeon_fifo_update_and_wait (rinfo, 64);
for (i=0; i<2000000; i++) {
if (((INREG(RBBM_STATUS) & GUI_ACTIVE)) == 0) {
@@ -581,8 +593,6 @@ static inline void _radeon_engine_idle(struct radeonfb_info *rinfo)
}
-#define radeon_engine_idle() _radeon_engine_idle(rinfo)
-#define radeon_fifo_wait(entries) _radeon_fifo_wait(rinfo,entries)
#define radeon_msleep(ms) _radeon_msleep(rinfo,ms)
@@ -612,6 +622,7 @@ extern void radeonfb_imageblit(struct fb_info *p, const struct fb_image *image);
extern int radeonfb_sync(struct fb_info *info);
extern void radeonfb_engine_init (struct radeonfb_info *rinfo);
extern void radeonfb_engine_reset(struct radeonfb_info *rinfo);
+extern void radeon_fixup_mem_offset(struct radeonfb_info *rinfo);
/* Other functions */
extern int radeon_screen_blank(struct radeonfb_info *rinfo, int blank, int mode_switch);
diff --git a/drivers/video/carminefb.c b/drivers/video/carminefb.c
index e15bb447440..c9b191319a9 100644
--- a/drivers/video/carminefb.c
+++ b/drivers/video/carminefb.c
@@ -535,7 +535,7 @@ static struct fb_ops carminefb_ops = {
.fb_setcolreg = carmine_setcolreg,
};
-static int alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
+static int __devinit alloc_carmine_fb(void __iomem *regs, void __iomem *smem_base,
int smem_offset, struct device *device, struct fb_info **rinfo)
{
int ret;
diff --git a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c
index e729fb27964..048b139f0e5 100644
--- a/drivers/video/cirrusfb.c
+++ b/drivers/video/cirrusfb.c
@@ -327,29 +327,7 @@ static const struct {
#endif /* CONFIG_ZORRO */
struct cirrusfb_regs {
- long freq;
- long nom;
- long den;
- long div;
- long multiplexing;
- long mclk;
- long divMCLK;
-
- long HorizRes; /* The x resolution in pixel */
- long HorizTotal;
- long HorizDispEnd;
- long HorizBlankStart;
- long HorizBlankEnd;
- long HorizSyncStart;
- long HorizSyncEnd;
-
- long VertRes; /* the physical y resolution in scanlines */
- long VertTotal;
- long VertDispEnd;
- long VertSyncStart;
- long VertSyncEnd;
- long VertBlankStart;
- long VertBlankEnd;
+ int multiplexing;
};
#ifdef CIRRUSFB_DEBUG
@@ -367,110 +345,13 @@ struct cirrusfb_info {
struct cirrusfb_regs currentmode;
int blank_mode;
+ u32 pseudo_palette[16];
- u32 pseudo_palette[16];
-
-#ifdef CONFIG_ZORRO
- struct zorro_dev *zdev;
-#endif
-#ifdef CONFIG_PCI
- struct pci_dev *pdev;
-#endif
void (*unmap)(struct fb_info *info);
};
-static unsigned cirrusfb_def_mode = 1;
-static int noaccel;
-
-/*
- * Predefined Video Modes
- */
-
-static const struct {
- const char *name;
- struct fb_var_screeninfo var;
-} cirrusfb_predefined[] = {
- {
- /* autodetect mode */
- .name = "Autodetect",
- }, {
- /* 640x480, 31.25 kHz, 60 Hz, 25 MHz PixClock */
- .name = "640x480",
- .var = {
- .xres = 640,
- .yres = 480,
- .xres_virtual = 640,
- .yres_virtual = 480,
- .bits_per_pixel = 8,
- .red = { .length = 8 },
- .green = { .length = 8 },
- .blue = { .length = 8 },
- .width = -1,
- .height = -1,
- .pixclock = 40000,
- .left_margin = 48,
- .right_margin = 16,
- .upper_margin = 32,
- .lower_margin = 8,
- .hsync_len = 96,
- .vsync_len = 4,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED
- }
- }, {
- /* 800x600, 48 kHz, 76 Hz, 50 MHz PixClock */
- .name = "800x600",
- .var = {
- .xres = 800,
- .yres = 600,
- .xres_virtual = 800,
- .yres_virtual = 600,
- .bits_per_pixel = 8,
- .red = { .length = 8 },
- .green = { .length = 8 },
- .blue = { .length = 8 },
- .width = -1,
- .height = -1,
- .pixclock = 20000,
- .left_margin = 128,
- .right_margin = 16,
- .upper_margin = 24,
- .lower_margin = 2,
- .hsync_len = 96,
- .vsync_len = 6,
- .vmode = FB_VMODE_NONINTERLACED
- }
- }, {
- /*
- * Modeline from XF86Config:
- * Mode "1024x768" 80 1024 1136 1340 1432 768 770 774 805
- */
- /* 1024x768, 55.8 kHz, 70 Hz, 80 MHz PixClock */
- .name = "1024x768",
- .var = {
- .xres = 1024,
- .yres = 768,
- .xres_virtual = 1024,
- .yres_virtual = 768,
- .bits_per_pixel = 8,
- .red = { .length = 8 },
- .green = { .length = 8 },
- .blue = { .length = 8 },
- .width = -1,
- .height = -1,
- .pixclock = 12500,
- .left_margin = 144,
- .right_margin = 32,
- .upper_margin = 30,
- .lower_margin = 2,
- .hsync_len = 192,
- .vsync_len = 6,
- .vmode = FB_VMODE_NONINTERLACED
- }
- }
-};
-
-#define NUM_TOTAL_MODES ARRAY_SIZE(cirrusfb_predefined)
+static int noaccel __devinitdata;
+static char *mode_option __devinitdata = "640x480@60";
/****************************************************************************/
/**** BEGIN PROTOTYPES ******************************************************/
@@ -514,10 +395,6 @@ static struct fb_ops cirrusfb_ops = {
.fb_imageblit = cirrusfb_imageblit,
};
-/*--- Hardware Specific Routines -------------------------------------------*/
-static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
- struct cirrusfb_regs *regs,
- struct fb_info *info);
/*--- Internal routines ----------------------------------------------------*/
static void init_vgachip(struct fb_info *info);
static void switch_monitor(struct cirrusfb_info *cinfo, int on);
@@ -546,9 +423,7 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
u_short width, u_short height,
u_char color, u_short line_length);
-static void bestclock(long freq, long *best,
- long *nom, long *den,
- long *div, long maxfreq);
+static void bestclock(long freq, int *nom, int *den, int *div);
#ifdef CIRRUSFB_DEBUG
static void cirrusfb_dump(void);
@@ -584,45 +459,28 @@ static int cirrusfb_release(struct fb_info *info, int user)
/****************************************************************************/
/**** BEGIN Hardware specific Routines **************************************/
-/* Get a good MCLK value */
-static long cirrusfb_get_mclk(long freq, int bpp, long *div)
+/* Check if the MCLK is not a better clock source */
+static int cirrusfb_check_mclk(struct cirrusfb_info *cinfo, long freq)
{
- long mclk;
+ long mclk = vga_rseq(cinfo->regbase, CL_SEQR1F) & 0x3f;
- assert(div != NULL);
-
- /* Calculate MCLK, in case VCLK is high enough to require > 50MHz.
- * Assume a 64-bit data path for now. The formula is:
- * ((B * PCLK * 2)/W) * 1.2
- * B = bytes per pixel, PCLK = pixclock, W = data width in bytes */
- mclk = ((bpp / 8) * freq * 2) / 4;
- mclk = (mclk * 12) / 10;
- if (mclk < 50000)
- mclk = 50000;
- DPRINTK("Use MCLK of %ld kHz\n", mclk);
-
- /* Calculate value for SR1F. Multiply by 2 so we can round up. */
- mclk = ((mclk * 16) / 14318);
- mclk = (mclk + 1) / 2;
- DPRINTK("Set SR1F[5:0] to 0x%lx\n", mclk);
+ /* Read MCLK value */
+ mclk = (14318 * mclk) >> 3;
+ DPRINTK("Read MCLK of %ld kHz\n", mclk);
/* Determine if we should use MCLK instead of VCLK, and if so, what we
- * should divide it by to get VCLK */
- switch (freq) {
- case 24751 ... 25249:
- *div = 2;
- DPRINTK("Using VCLK = MCLK/2\n");
- break;
- case 49501 ... 50499:
- *div = 1;
+ * should divide it by to get VCLK
+ */
+
+ if (abs(freq - mclk) < 250) {
DPRINTK("Using VCLK = MCLK\n");
- break;
- default:
- *div = 0;
- break;
+ return 1;
+ } else if (abs(freq - (mclk / 2)) < 250) {
+ DPRINTK("Using VCLK = MCLK/2\n");
+ return 2;
}
- return mclk;
+ return 0;
}
static int cirrusfb_check_var(struct fb_var_screeninfo *var,
@@ -638,7 +496,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
break; /* 8 pixel per byte, only 1/4th of mem usable */
case 8:
case 16:
- case 24:
case 32:
break; /* 1 pixel == 1 byte */
default:
@@ -713,7 +570,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
var->blue.length = 5;
break;
- case 24:
case 32:
if (isPReP) {
var->red.offset = 8;
@@ -767,8 +623,6 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
long maxclock;
int maxclockidx = var->bits_per_pixel >> 3;
struct cirrusfb_info *cinfo = info->par;
- int xres, hfront, hsync, hback;
- int yres, vfront, vsync, vback;
switch (var->bits_per_pixel) {
case 1:
@@ -782,10 +636,9 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
break;
case 16:
- case 24:
case 32:
info->fix.line_length = var->xres_virtual * maxclockidx;
- info->fix.visual = FB_VISUAL_DIRECTCOLOR;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
break;
default:
@@ -827,90 +680,33 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
switch (var->bits_per_pixel) {
case 16:
case 32:
- if (regs->HorizRes <= 800)
+ if (var->xres <= 800)
/* Xbh has this type of clock for 32-bit */
freq /= 2;
break;
}
#endif
-
- bestclock(freq, &regs->freq, &regs->nom, &regs->den, &regs->div,
- maxclock);
- regs->mclk = cirrusfb_get_mclk(freq, var->bits_per_pixel,
- &regs->divMCLK);
-
- xres = var->xres;
- hfront = var->right_margin;
- hsync = var->hsync_len;
- hback = var->left_margin;
-
- yres = var->yres;
- vfront = var->lower_margin;
- vsync = var->vsync_len;
- vback = var->upper_margin;
-
- if (var->vmode & FB_VMODE_DOUBLE) {
- yres *= 2;
- vfront *= 2;
- vsync *= 2;
- vback *= 2;
- } else if (var->vmode & FB_VMODE_INTERLACED) {
- yres = (yres + 1) / 2;
- vfront = (vfront + 1) / 2;
- vsync = (vsync + 1) / 2;
- vback = (vback + 1) / 2;
- }
- regs->HorizRes = xres;
- regs->HorizTotal = (xres + hfront + hsync + hback) / 8 - 5;
- regs->HorizDispEnd = xres / 8 - 1;
- regs->HorizBlankStart = xres / 8;
- /* does not count with "-5" */
- regs->HorizBlankEnd = regs->HorizTotal + 5;
- regs->HorizSyncStart = (xres + hfront) / 8 + 1;
- regs->HorizSyncEnd = (xres + hfront + hsync) / 8 + 1;
-
- regs->VertRes = yres;
- regs->VertTotal = yres + vfront + vsync + vback - 2;
- regs->VertDispEnd = yres - 1;
- regs->VertBlankStart = yres;
- regs->VertBlankEnd = regs->VertTotal;
- regs->VertSyncStart = yres + vfront - 1;
- regs->VertSyncEnd = yres + vfront + vsync - 1;
-
- if (regs->VertRes >= 1024) {
- regs->VertTotal /= 2;
- regs->VertSyncStart /= 2;
- regs->VertSyncEnd /= 2;
- regs->VertDispEnd /= 2;
- }
- if (regs->multiplexing) {
- regs->HorizTotal /= 2;
- regs->HorizSyncStart /= 2;
- regs->HorizSyncEnd /= 2;
- regs->HorizDispEnd /= 2;
- }
-
return 0;
}
-static void cirrusfb_set_mclk(const struct cirrusfb_info *cinfo, int val,
- int div)
+static void cirrusfb_set_mclk_as_source(const struct cirrusfb_info *cinfo,
+ int div)
{
+ unsigned char old1f, old1e;
assert(cinfo != NULL);
+ old1f = vga_rseq(cinfo->regbase, CL_SEQR1F) & ~0x40;
- if (div == 2) {
- /* VCLK = MCLK/2 */
- unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
- vga_wseq(cinfo->regbase, CL_SEQR1E, old | 0x1);
- vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
- } else if (div == 1) {
- /* VCLK = MCLK */
- unsigned char old = vga_rseq(cinfo->regbase, CL_SEQR1E);
- vga_wseq(cinfo->regbase, CL_SEQR1E, old & ~0x1);
- vga_wseq(cinfo->regbase, CL_SEQR1F, 0x40 | (val & 0x3f));
- } else {
- vga_wseq(cinfo->regbase, CL_SEQR1F, val & 0x3f);
+ if (div) {
+ DPRINTK("Set %s as pixclock source.\n",
+ (div == 2) ? "MCLK/2" : "MCLK");
+ old1f |= 0x40;
+ old1e = vga_rseq(cinfo->regbase, CL_SEQR1E) & ~0x1;
+ if (div == 2)
+ old1e |= 1;
+
+ vga_wseq(cinfo->regbase, CL_SEQR1E, old1e);
}
+ vga_wseq(cinfo->regbase, CL_SEQR1F, old1f);
}
/*************************************************************************
@@ -927,6 +723,10 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
unsigned char tmp;
int offset = 0, err;
const struct cirrusfb_board_info_rec *bi;
+ int hdispend, hsyncstart, hsyncend, htotal;
+ int yres, vdispend, vsyncstart, vsyncend, vtotal;
+ long freq;
+ int nom, den, div;
DPRINTK("ENTER\n");
DPRINTK("Requested mode: %dx%dx%d\n",
@@ -944,76 +744,117 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
bi = &cirrusfb_board_info[cinfo->btype];
+ hsyncstart = var->xres + var->right_margin;
+ hsyncend = hsyncstart + var->hsync_len;
+ htotal = (hsyncend + var->left_margin) / 8 - 5;
+ hdispend = var->xres / 8 - 1;
+ hsyncstart = hsyncstart / 8 + 1;
+ hsyncend = hsyncend / 8 + 1;
+
+ yres = var->yres;
+ vsyncstart = yres + var->lower_margin;
+ vsyncend = vsyncstart + var->vsync_len;
+ vtotal = vsyncend + var->upper_margin;
+ vdispend = yres - 1;
+
+ if (var->vmode & FB_VMODE_DOUBLE) {
+ yres *= 2;
+ vsyncstart *= 2;
+ vsyncend *= 2;
+ vtotal *= 2;
+ } else if (var->vmode & FB_VMODE_INTERLACED) {
+ yres = (yres + 1) / 2;
+ vsyncstart = (vsyncstart + 1) / 2;
+ vsyncend = (vsyncend + 1) / 2;
+ vtotal = (vtotal + 1) / 2;
+ }
+
+ vtotal -= 2;
+ vsyncstart -= 1;
+ vsyncend -= 1;
+
+ if (yres >= 1024) {
+ vtotal /= 2;
+ vsyncstart /= 2;
+ vsyncend /= 2;
+ vdispend /= 2;
+ }
+ if (regs.multiplexing) {
+ htotal /= 2;
+ hsyncstart /= 2;
+ hsyncend /= 2;
+ hdispend /= 2;
+ }
/* unlock register VGA_CRTC_H_TOTAL..CRT7 */
vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, 0x20); /* previously: 0x00) */
/* if debugging is enabled, all parameters get output before writing */
- DPRINTK("CRT0: %ld\n", regs.HorizTotal);
- vga_wcrt(regbase, VGA_CRTC_H_TOTAL, regs.HorizTotal);
+ DPRINTK("CRT0: %d\n", htotal);
+ vga_wcrt(regbase, VGA_CRTC_H_TOTAL, htotal);
- DPRINTK("CRT1: %ld\n", regs.HorizDispEnd);
- vga_wcrt(regbase, VGA_CRTC_H_DISP, regs.HorizDispEnd);
+ DPRINTK("CRT1: %d\n", hdispend);
+ vga_wcrt(regbase, VGA_CRTC_H_DISP, hdispend);
- DPRINTK("CRT2: %ld\n", regs.HorizBlankStart);
- vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, regs.HorizBlankStart);
+ DPRINTK("CRT2: %d\n", var->xres / 8);
+ vga_wcrt(regbase, VGA_CRTC_H_BLANK_START, var->xres / 8);
/* + 128: Compatible read */
- DPRINTK("CRT3: 128+%ld\n", regs.HorizBlankEnd % 32);
+ DPRINTK("CRT3: 128+%d\n", (htotal + 5) % 32);
vga_wcrt(regbase, VGA_CRTC_H_BLANK_END,
- 128 + (regs.HorizBlankEnd % 32));
+ 128 + ((htotal + 5) % 32));
- DPRINTK("CRT4: %ld\n", regs.HorizSyncStart);
- vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, regs.HorizSyncStart);
+ DPRINTK("CRT4: %d\n", hsyncstart);
+ vga_wcrt(regbase, VGA_CRTC_H_SYNC_START, hsyncstart);
- tmp = regs.HorizSyncEnd % 32;
- if (regs.HorizBlankEnd & 32)
+ tmp = hsyncend % 32;
+ if ((htotal + 5) & 32)
tmp += 128;
DPRINTK("CRT5: %d\n", tmp);
vga_wcrt(regbase, VGA_CRTC_H_SYNC_END, tmp);
- DPRINTK("CRT6: %ld\n", regs.VertTotal & 0xff);
- vga_wcrt(regbase, VGA_CRTC_V_TOTAL, (regs.VertTotal & 0xff));
+ DPRINTK("CRT6: %d\n", vtotal & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_TOTAL, vtotal & 0xff);
tmp = 16; /* LineCompare bit #9 */
- if (regs.VertTotal & 256)
+ if (vtotal & 256)
tmp |= 1;
- if (regs.VertDispEnd & 256)
+ if (vdispend & 256)
tmp |= 2;
- if (regs.VertSyncStart & 256)
+ if (vsyncstart & 256)
tmp |= 4;
- if (regs.VertBlankStart & 256)
+ if ((vdispend + 1) & 256)
tmp |= 8;
- if (regs.VertTotal & 512)
+ if (vtotal & 512)
tmp |= 32;
- if (regs.VertDispEnd & 512)
+ if (vdispend & 512)
tmp |= 64;
- if (regs.VertSyncStart & 512)
+ if (vsyncstart & 512)
tmp |= 128;
DPRINTK("CRT7: %d\n", tmp);
vga_wcrt(regbase, VGA_CRTC_OVERFLOW, tmp);
tmp = 0x40; /* LineCompare bit #8 */
- if (regs.VertBlankStart & 512)
+ if ((vdispend + 1) & 512)
tmp |= 0x20;
if (var->vmode & FB_VMODE_DOUBLE)
tmp |= 0x80;
DPRINTK("CRT9: %d\n", tmp);
vga_wcrt(regbase, VGA_CRTC_MAX_SCAN, tmp);
- DPRINTK("CRT10: %ld\n", regs.VertSyncStart & 0xff);
- vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, regs.VertSyncStart & 0xff);
+ DPRINTK("CRT10: %d\n", vsyncstart & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_SYNC_START, vsyncstart & 0xff);
- DPRINTK("CRT11: 64+32+%ld\n", regs.VertSyncEnd % 16);
- vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, regs.VertSyncEnd % 16 + 64 + 32);
+ DPRINTK("CRT11: 64+32+%d\n", vsyncend % 16);
+ vga_wcrt(regbase, VGA_CRTC_V_SYNC_END, vsyncend % 16 + 64 + 32);
- DPRINTK("CRT12: %ld\n", regs.VertDispEnd & 0xff);
- vga_wcrt(regbase, VGA_CRTC_V_DISP_END, regs.VertDispEnd & 0xff);
+ DPRINTK("CRT12: %d\n", vdispend & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_DISP_END, vdispend & 0xff);
- DPRINTK("CRT15: %ld\n", regs.VertBlankStart & 0xff);
- vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, regs.VertBlankStart & 0xff);
+ DPRINTK("CRT15: %d\n", (vdispend + 1) & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_BLANK_START, (vdispend + 1) & 0xff);
- DPRINTK("CRT16: %ld\n", regs.VertBlankEnd & 0xff);
- vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, regs.VertBlankEnd & 0xff);
+ DPRINTK("CRT16: %d\n", vtotal & 0xff);
+ vga_wcrt(regbase, VGA_CRTC_V_BLANK_END, vtotal & 0xff);
DPRINTK("CRT18: 0xff\n");
vga_wcrt(regbase, VGA_CRTC_LINE_COMPARE, 0xff);
@@ -1021,38 +862,53 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
tmp = 0;
if (var->vmode & FB_VMODE_INTERLACED)
tmp |= 1;
- if (regs.HorizBlankEnd & 64)
+ if ((htotal + 5) & 64)
tmp |= 16;
- if (regs.HorizBlankEnd & 128)
+ if ((htotal + 5) & 128)
tmp |= 32;
- if (regs.VertBlankEnd & 256)
+ if (vtotal & 256)
tmp |= 64;
- if (regs.VertBlankEnd & 512)
+ if (vtotal & 512)
tmp |= 128;
DPRINTK("CRT1a: %d\n", tmp);
vga_wcrt(regbase, CL_CRT1A, tmp);
+ freq = PICOS2KHZ(var->pixclock);
+ bestclock(freq, &nom, &den, &div);
+
/* set VCLK0 */
/* hardware RefClock: 14.31818 MHz */
/* formula: VClk = (OSC * N) / (D * (1+P)) */
/* Example: VClk = (14.31818 * 91) / (23 * (1+1)) = 28.325 MHz */
- vga_wseq(regbase, CL_SEQRB, regs.nom);
- tmp = regs.den << 1;
- if (regs.div != 0)
- tmp |= 1;
+ if (cinfo->btype == BT_ALPINE) {
+ /* if freq is close to mclk or mclk/2 select mclk
+ * as clock source
+ */
+ int divMCLK = cirrusfb_check_mclk(cinfo, freq);
+ if (divMCLK) {
+ nom = 0;
+ cirrusfb_set_mclk_as_source(cinfo, divMCLK);
+ }
+ }
+ if (nom) {
+ vga_wseq(regbase, CL_SEQRB, nom);
+ tmp = den << 1;
+ if (div != 0)
+ tmp |= 1;
- /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
- if ((cinfo->btype == BT_SD64) ||
- (cinfo->btype == BT_ALPINE) ||
- (cinfo->btype == BT_GD5480))
- tmp |= 0x80;
+ /* 6 bit denom; ONLY 5434!!! (bugged me 10 days) */
+ if ((cinfo->btype == BT_SD64) ||
+ (cinfo->btype == BT_ALPINE) ||
+ (cinfo->btype == BT_GD5480))
+ tmp |= 0x80;
- DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
- vga_wseq(regbase, CL_SEQR1B, tmp);
+ DPRINTK("CL_SEQR1B: %ld\n", (long) tmp);
+ vga_wseq(regbase, CL_SEQR1B, tmp);
+ }
- if (regs.VertRes >= 1024)
+ if (yres >= 1024)
/* 1280x1024 */
vga_wcrt(regbase, VGA_CRTC_MODE, 0xc7);
else
@@ -1066,7 +922,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
/* don't know if it would hurt to also program this if no interlaced */
/* mode is used, but I feel better this way.. :-) */
if (var->vmode & FB_VMODE_INTERLACED)
- vga_wcrt(regbase, VGA_CRTC_REGS, regs.HorizTotal / 2);
+ vga_wcrt(regbase, VGA_CRTC_REGS, htotal / 2);
else
vga_wcrt(regbase, VGA_CRTC_REGS, 0x00); /* interlace control */
@@ -1240,7 +1096,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
case BT_ALPINE:
DPRINTK(" (for GD543x)\n");
- cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
/* We already set SRF and SR1F */
break;
@@ -1312,11 +1167,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
case BT_ALPINE:
DPRINTK(" (for GD543x)\n");
- if (regs.HorizRes >= 1024)
- vga_wseq(regbase, CL_SEQR7, 0xa7);
- else
- vga_wseq(regbase, CL_SEQR7, 0xa3);
- cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
+ vga_wseq(regbase, CL_SEQR7, 0xa7);
break;
case BT_GD5480:
@@ -1360,7 +1211,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
*/
else if (var->bits_per_pixel == 32) {
- DPRINTK("cirrusfb: preparing for 24/32 bit deep display\n");
+ DPRINTK("cirrusfb: preparing for 32 bit deep display\n");
switch (cinfo->btype) {
case BT_SD64:
/* Extended Sequencer Mode: 256c col. mode */
@@ -1394,7 +1245,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
case BT_ALPINE:
DPRINTK(" (for GD543x)\n");
vga_wseq(regbase, CL_SEQR7, 0xa9);
- cirrusfb_set_mclk(cinfo, regs.mclk, regs.divMCLK);
break;
case BT_GD5480:
@@ -1949,8 +1799,6 @@ static void init_vgachip(struct fb_info *info)
/* misc... */
WHDR(cinfo, 0); /* Hidden DAC register: - */
- printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
- info->screen_size);
DPRINTK("EXIT\n");
return;
}
@@ -2122,7 +1970,7 @@ static int release_io_ports;
* based on the DRAM bandwidth bit and DRAM bank switching bit. This
* works with 1MB, 2MB and 4MB configurations (which the Motorola boards
* seem to have. */
-static unsigned int cirrusfb_get_memsize(u8 __iomem *regbase)
+static unsigned int __devinit cirrusfb_get_memsize(u8 __iomem *regbase)
{
unsigned long mem;
unsigned char SRF;
@@ -2188,8 +2036,7 @@ static void get_pci_addrs(const struct pci_dev *pdev,
static void cirrusfb_pci_unmap(struct fb_info *info)
{
- struct cirrusfb_info *cinfo = info->par;
- struct pci_dev *pdev = cinfo->pdev;
+ struct pci_dev *pdev = to_pci_dev(info->device);
iounmap(info->screen_base);
#if 0 /* if system didn't claim this region, we would... */
@@ -2205,20 +2052,22 @@ static void cirrusfb_pci_unmap(struct fb_info *info)
static void __devexit cirrusfb_zorro_unmap(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
- zorro_release_device(cinfo->zdev);
+ struct zorro_dev *zdev = to_zorro_dev(info->device);
+
+ zorro_release_device(zdev);
if (cinfo->btype == BT_PICASSO4) {
cinfo->regbase -= 0x600000;
iounmap((void *)cinfo->regbase);
iounmap(info->screen_base);
} else {
- if (zorro_resource_start(cinfo->zdev) > 0x01000000)
+ if (zorro_resource_start(zdev) > 0x01000000)
iounmap(info->screen_base);
}
}
#endif /* CONFIG_ZORRO */
-static int cirrusfb_set_fbinfo(struct fb_info *info)
+static int __devinit cirrusfb_set_fbinfo(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
struct fb_var_screeninfo *var = &info->var;
@@ -2235,7 +2084,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info)
if (cinfo->btype == BT_GD5480) {
if (var->bits_per_pixel == 16)
info->screen_base += 1 * MB_;
- if (var->bits_per_pixel == 24 || var->bits_per_pixel == 32)
+ if (var->bits_per_pixel == 32)
info->screen_base += 2 * MB_;
}
@@ -2262,7 +2111,7 @@ static int cirrusfb_set_fbinfo(struct fb_info *info)
return 0;
}
-static int cirrusfb_register(struct fb_info *info)
+static int __devinit cirrusfb_register(struct fb_info *info)
{
struct cirrusfb_info *cinfo = info->par;
int err;
@@ -2278,23 +2127,27 @@ static int cirrusfb_register(struct fb_info *info)
/* sanity checks */
assert(btype != BT_NONE);
+ /* set all the vital stuff */
+ cirrusfb_set_fbinfo(info);
+
DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
- /* Make pretend we've set the var so our structures are in a "good" */
- /* state, even though we haven't written the mode to the hw yet... */
- info->var = cirrusfb_predefined[cirrusfb_def_mode].var;
+ err = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
+ if (!err) {
+ DPRINTK("wrong initial video mode\n");
+ err = -EINVAL;
+ goto err_dealloc_cmap;
+ }
+
info->var.activate = FB_ACTIVATE_NOW;
err = cirrusfb_decode_var(&info->var, &cinfo->currentmode, info);
if (err < 0) {
/* should never happen */
DPRINTK("choking on default var... umm, no good.\n");
- goto err_unmap_cirrusfb;
+ goto err_dealloc_cmap;
}
- /* set all the vital stuff */
- cirrusfb_set_fbinfo(info);
-
err = register_framebuffer(info);
if (err < 0) {
printk(KERN_ERR "cirrusfb: could not register "
@@ -2307,7 +2160,6 @@ static int cirrusfb_register(struct fb_info *info)
err_dealloc_cmap:
fb_dealloc_cmap(&info->cmap);
-err_unmap_cirrusfb:
cinfo->unmap(info);
framebuffer_release(info);
return err;
@@ -2330,8 +2182,8 @@ static void __devexit cirrusfb_cleanup(struct fb_info *info)
}
#ifdef CONFIG_PCI
-static int cirrusfb_pci_register(struct pci_dev *pdev,
- const struct pci_device_id *ent)
+static int __devinit cirrusfb_pci_register(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct cirrusfb_info *cinfo;
struct fb_info *info;
@@ -2353,7 +2205,6 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
}
cinfo = info->par;
- cinfo->pdev = pdev;
cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
@@ -2459,8 +2310,8 @@ static struct pci_driver cirrusfb_pci_driver = {
#endif /* CONFIG_PCI */
#ifdef CONFIG_ZORRO
-static int cirrusfb_zorro_register(struct zorro_dev *z,
- const struct zorro_device_id *ent)
+static int __devinit cirrusfb_zorro_register(struct zorro_dev *z,
+ const struct zorro_device_id *ent)
{
struct cirrusfb_info *cinfo;
struct fb_info *info;
@@ -2489,7 +2340,6 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
assert(z);
assert(btype != BT_NONE);
- cinfo->zdev = z;
board_addr = zorro_resource_start(z);
board_size = zorro_resource_len(z);
info->screen_size = size;
@@ -2621,17 +2471,17 @@ static int __init cirrusfb_setup(char *options) {
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
+ if (!*this_opt)
+ continue;
DPRINTK("cirrusfb_setup: option '%s'\n", this_opt);
- for (i = 0; i < NUM_TOTAL_MODES; i++) {
- sprintf(s, "mode:%s", cirrusfb_predefined[i].name);
- if (strcmp(this_opt, s) == 0)
- cirrusfb_def_mode = i;
- }
if (!strcmp(this_opt, "noaccel"))
noaccel = 1;
+ else if (!strncmp(this_opt, "mode:", 5))
+ mode_option = this_opt + 5;
+ else
+ mode_option = this_opt;
}
return 0;
}
@@ -2657,6 +2507,11 @@ static void __exit cirrusfb_exit(void)
module_init(cirrusfb_init);
+module_param(mode_option, charp, 0);
+MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
+module_param(noaccel, bool, 0);
+MODULE_PARM_DESC(noaccel, "Disable acceleration");
+
#ifdef MODULE
module_exit(cirrusfb_exit);
#endif
@@ -3050,16 +2905,14 @@ static void cirrusfb_RectFill(u8 __iomem *regbase, int bits_per_pixel,
* bestclock() - determine closest possible clock lower(?) than the
* desired pixel clock
**************************************************************************/
-static void bestclock(long freq, long *best, long *nom,
- long *den, long *div, long maxfreq)
+static void bestclock(long freq, int *nom, int *den, int *div)
{
- long n, h, d, f;
+ int n, d;
+ long h, diff;
- assert(best != NULL);
assert(nom != NULL);
assert(den != NULL);
assert(div != NULL);
- assert(maxfreq > 0);
*nom = 0;
*den = 0;
@@ -3070,51 +2923,47 @@ static void bestclock(long freq, long *best, long *nom,
if (freq < 8000)
freq = 8000;
- if (freq > maxfreq)
- freq = maxfreq;
-
- *best = 0;
- f = freq * 10;
+ diff = freq;
for (n = 32; n < 128; n++) {
- d = (143181 * n) / f;
+ int s = 0;
+
+ d = (14318 * n) / freq;
if ((d >= 7) && (d <= 63)) {
- if (d > 31)
- d = (d / 2) * 2;
- h = (14318 * n) / d;
- if (abs(h - freq) < abs(*best - freq)) {
- *best = h;
+ int temp = d;
+
+ if (temp > 31) {
+ s = 1;
+ temp >>= 1;
+ }
+ h = ((14318 * n) / temp) >> s;
+ h = h > freq ? h - freq : freq - h;
+ if (h < diff) {
+ diff = h;
*nom = n;
- if (d < 32) {
- *den = d;
- *div = 0;
- } else {
- *den = d / 2;
- *div = 1;
- }
+ *den = temp;
+ *div = s;
}
}
- d = DIV_ROUND_UP(143181 * n, f);
+ d++;
if ((d >= 7) && (d <= 63)) {
- if (d > 31)
- d = (d / 2) * 2;
- h = (14318 * n) / d;
- if (abs(h - freq) < abs(*best - freq)) {
- *best = h;
+ if (d > 31) {
+ s = 1;
+ d >>= 1;
+ }
+ h = ((14318 * n) / d) >> s;
+ h = h > freq ? h - freq : freq - h;
+ if (h < diff) {
+ diff = h;
*nom = n;
- if (d < 32) {
- *den = d;
- *div = 0;
- } else {
- *den = d / 2;
- *div = 1;
- }
+ *den = d;
+ *div = s;
}
}
}
DPRINTK("Best possible values for given frequency:\n");
- DPRINTK(" best: %ld kHz nom: %ld den: %ld div: %ld\n",
+ DPRINTK(" freq: %ld kHz nom: %d den: %d div: %d\n",
freq, *nom, *den, *div);
DPRINTK("EXIT\n");
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 9cbff84b787..93a080e827c 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1855,8 +1855,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct display *p = &fb_display[vc->vc_num];
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
- unsigned short saved_ec;
- int ret;
if (fbcon_is_inactive(vc, info))
return -EINVAL;
@@ -1869,11 +1867,6 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
* whole screen (prevents flicker).
*/
- saved_ec = vc->vc_video_erase_char;
- vc->vc_video_erase_char = vc->vc_scrl_erase_char;
-
- ret = 0;
-
switch (dir) {
case SM_UP:
if (count > vc->vc_rows) /* Maximum realistic size */
@@ -1890,9 +1883,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -1962,10 +1955,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
- break;
+ return 1;
}
break;
@@ -1982,9 +1974,9 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
+ return 1;
break;
case SCROLL_WRAP_MOVE:
@@ -2052,15 +2044,12 @@ static int fbcon_scroll(struct vc_data *vc, int t, int b, int dir,
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_scrl_erase_char,
+ vc->vc_video_erase_char,
vc->vc_size_row * count);
- ret = 1;
- break;
+ return 1;
}
- break;
}
- vc->vc_video_erase_char = saved_ec;
- return ret;
+ return 0;
}
@@ -2522,9 +2511,6 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
c = vc->vc_video_erase_char;
vc->vc_video_erase_char =
((c & 0xfe00) >> 1) | (c & 0xff);
- c = vc->vc_scrl_erase_char;
- vc->vc_scrl_erase_char =
- ((c & 0xFE00) >> 1) | (c & 0xFF);
vc->vc_attr >>= 1;
}
} else if (!vc->vc_hi_font_mask && cnt == 512) {
@@ -2555,14 +2541,9 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h,
if (vc->vc_can_do_color) {
vc->vc_video_erase_char =
((c & 0xff00) << 1) | (c & 0xff);
- c = vc->vc_scrl_erase_char;
- vc->vc_scrl_erase_char =
- ((c & 0xFF00) << 1) | (c & 0xFF);
vc->vc_attr <<= 1;
- } else {
+ } else
vc->vc_video_erase_char = c & ~0x100;
- vc->vc_scrl_erase_char = c & ~0x100;
- }
}
}
@@ -2996,8 +2977,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
p = &fb_display[vc->vc_num];
set_blitting_type(vc, info);
var_to_display(p, &info->var, info);
- cols = FBCON_SWAP(p->rotate, info->var.xres, info->var.yres);
- rows = FBCON_SWAP(p->rotate, info->var.yres, info->var.xres);
+ cols = FBCON_SWAP(ops->rotate, info->var.xres, info->var.yres);
+ rows = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
cols /= vc->vc_font.width;
rows /= vc->vc_font.height;
vc_resize(vc, cols, rows);
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index 9901064199b..dd3eaaad444 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -533,7 +533,7 @@ static void mdacon_cursor(struct vc_data *c, int mode)
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
{
- u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
+ u16 eattr = mda_convert_attr(c->vc_video_erase_char);
if (!lines)
return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 4055dbdd1b4..491c1c1baf4 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -170,12 +170,12 @@ static int sticon_scroll(struct vc_data *conp, int t, int b, int dir, int count)
switch (dir) {
case SM_UP:
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+ sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
case SM_DOWN:
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
+ sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
break;
}
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index bd1f57b259d..448d209a0bf 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -239,8 +239,7 @@ static void vgacon_restore_screen(struct vc_data *c)
static int vgacon_scrolldelta(struct vc_data *c, int lines)
{
- int start, end, count, soff, diff;
- void *d, *s;
+ int start, end, count, soff;
if (!lines) {
c->vc_visible_origin = c->vc_origin;
@@ -287,29 +286,29 @@ static int vgacon_scrolldelta(struct vc_data *c, int lines)
if (count > c->vc_rows)
count = c->vc_rows;
- diff = c->vc_rows - count;
+ if (count) {
+ int copysize;
- d = (void *) c->vc_origin;
- s = (void *) c->vc_screenbuf;
+ int diff = c->vc_rows - count;
+ void *d = (void *) c->vc_origin;
+ void *s = (void *) c->vc_screenbuf;
- while (count--) {
- scr_memcpyw(d, vgacon_scrollback + soff, c->vc_size_row);
- d += c->vc_size_row;
- soff += c->vc_size_row;
+ count *= c->vc_size_row;
+ /* how much memory to end of buffer left? */
+ copysize = min(count, vgacon_scrollback_size - soff);
+ scr_memcpyw(d, vgacon_scrollback + soff, copysize);
+ d += copysize;
+ count -= copysize;
- if (soff >= vgacon_scrollback_size)
- soff = 0;
- }
+ if (count) {
+ scr_memcpyw(d, vgacon_scrollback, count);
+ d += count;
+ }
- if (diff == c->vc_rows) {
+ if (diff)
+ scr_memcpyw(d, s, diff * c->vc_size_row);
+ } else
vgacon_cursor(c, CM_MOVE);
- } else {
- while (diff--) {
- scr_memcpyw(d, s, c->vc_size_row);
- d += c->vc_size_row;
- s += c->vc_size_row;
- }
- }
return 1;
}
@@ -1350,7 +1349,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin += delta;
scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
- delta), c->vc_scrl_erase_char,
+ delta), c->vc_video_erase_char,
delta);
} else {
if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1362,7 @@ static int vgacon_scroll(struct vc_data *c, int t, int b, int dir,
} else
c->vc_origin -= delta;
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
- scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
+ scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
delta);
}
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
diff --git a/drivers/video/efifb.c b/drivers/video/efifb.c
index bd779ae44b1..daf9b81878a 100644
--- a/drivers/video/efifb.c
+++ b/drivers/video/efifb.c
@@ -12,6 +12,7 @@
#include <linux/fb.h>
#include <linux/platform_device.h>
#include <linux/screen_info.h>
+#include <linux/dmi.h>
#include <video/vga.h>
@@ -33,6 +34,105 @@ static struct fb_fix_screeninfo efifb_fix __initdata = {
.visual = FB_VISUAL_TRUECOLOR,
};
+enum {
+ M_I17, /* 17-Inch iMac */
+ M_I20, /* 20-Inch iMac */
+ M_I20_SR, /* 20-Inch iMac (Santa Rosa) */
+ M_I24, /* 24-Inch iMac */
+ M_MINI, /* Mac Mini */
+ M_MB, /* MacBook */
+ M_MB_2, /* MacBook, 2nd rev. */
+ M_MB_3, /* MacBook, 3rd rev. */
+ M_MB_SR, /* MacBook, 2nd gen, (Santa Rosa) */
+ M_MBA, /* MacBook Air */
+ M_MBP, /* MacBook Pro */
+ M_MBP_2, /* MacBook Pro 2nd gen */
+ M_MBP_SR, /* MacBook Pro (Santa Rosa) */
+ M_MBP_4, /* MacBook Pro, 4th gen */
+ M_UNKNOWN /* placeholder */
+};
+
+static struct efifb_dmi_info {
+ char *optname;
+ unsigned long base;
+ int stride;
+ int width;
+ int height;
+} dmi_list[] = {
+ [M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 },
+ [M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
+ [M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
+ [M_I24] = { "i24", 0x80010000, 2048 * 4, 1920, 1200 }, /* guess */
+ [M_MINI]= { "mini", 0x80000000, 2048 * 4, 1024, 768 },
+ [M_MB] = { "macbook", 0x80000000, 2048 * 4, 1280, 800 },
+ [M_MBA] = { "mba", 0x80000000, 2048 * 4, 1280, 800 },
+ [M_MBP] = { "mbp", 0x80010000, 1472 * 4, 1440, 900 },
+ [M_MBP_2] = { "mbp2", 0, 0, 0, 0 }, /* placeholder */
+ [M_MBP_SR] = { "mbp3", 0x80030000, 2048 * 4, 1440, 900 },
+ [M_MBP_4] = { "mbp4", 0xc0060000, 2048 * 4, 1920, 1200 },
+ [M_UNKNOWN] = { NULL, 0, 0, 0, 0 }
+};
+
+static int set_system(const struct dmi_system_id *id);
+
+#define EFIFB_DMI_SYSTEM_ID(vendor, name, enumid) \
+ { set_system, name, { \
+ DMI_MATCH(DMI_BIOS_VENDOR, vendor), \
+ DMI_MATCH(DMI_PRODUCT_NAME, name) }, \
+ &dmi_list[enumid] }
+
+static struct dmi_system_id __initdata dmi_system_table[] = {
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
+ /* At least one of these two will be right; maybe both? */
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac5,1", M_I20),
+ /* At least one of these two will be right; maybe both? */
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac6,1", M_I24),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac6,1", M_I24),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "iMac7,1", M_I20_SR),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "Macmini1,1", M_MINI),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook1,1", M_MB),
+ /* At least one of these two will be right; maybe both? */
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook2,1", M_MB),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook2,1", M_MB),
+ /* At least one of these two will be right; maybe both? */
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBook3,1", M_MB),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook3,1", M_MB),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBook4,1", M_MB),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookAir1,1", M_MBA),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro1,1", M_MBP),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro2,1", M_MBP_2),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro2,1", M_MBP_2),
+ EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "MacBookPro3,1", M_MBP_SR),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro3,1", M_MBP_SR),
+ EFIFB_DMI_SYSTEM_ID("Apple Inc.", "MacBookPro4,1", M_MBP_4),
+ {},
+};
+
+static int set_system(const struct dmi_system_id *id)
+{
+ struct efifb_dmi_info *info = id->driver_data;
+ if (info->base == 0)
+ return -ENODEV;
+
+ printk(KERN_INFO "efifb: dmi detected %s - framebuffer at %p "
+ "(%dx%d, stride %d)\n", id->ident,
+ (void *)info->base, info->width, info->height,
+ info->stride);
+
+ /* Trust the bootloader over the DMI tables */
+ if (screen_info.lfb_base == 0)
+ screen_info.lfb_base = info->base;
+ if (screen_info.lfb_linelength == 0)
+ screen_info.lfb_linelength = info->stride;
+ if (screen_info.lfb_width == 0)
+ screen_info.lfb_width = info->width;
+ if (screen_info.lfb_height == 0)
+ screen_info.lfb_height = info->height;
+
+ return 0;
+}
+
static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp,
struct fb_info *info)
@@ -67,6 +167,38 @@ static struct fb_ops efifb_ops = {
.fb_imageblit = cfb_imageblit,
};
+static int __init efifb_setup(char *options)
+{
+ char *this_opt;
+ int i;
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt) continue;
+
+ for (i = 0; i < M_UNKNOWN; i++) {
+ if (!strcmp(this_opt, dmi_list[i].optname) &&
+ dmi_list[i].base != 0) {
+ screen_info.lfb_base = dmi_list[i].base;
+ screen_info.lfb_linelength = dmi_list[i].stride;
+ screen_info.lfb_width = dmi_list[i].width;
+ screen_info.lfb_height = dmi_list[i].height;
+ }
+ }
+ if (!strncmp(this_opt, "base:", 5))
+ screen_info.lfb_base = simple_strtoul(this_opt+5, NULL, 0);
+ else if (!strncmp(this_opt, "stride:", 7))
+ screen_info.lfb_linelength = simple_strtoul(this_opt+7, NULL, 0) * 4;
+ else if (!strncmp(this_opt, "height:", 7))
+ screen_info.lfb_height = simple_strtoul(this_opt+7, NULL, 0);
+ else if (!strncmp(this_opt, "width:", 6))
+ screen_info.lfb_width = simple_strtoul(this_opt+6, NULL, 0);
+ }
+ return 0;
+}
+
static int __init efifb_probe(struct platform_device *dev)
{
struct fb_info *info;
@@ -74,6 +206,26 @@ static int __init efifb_probe(struct platform_device *dev)
unsigned int size_vmode;
unsigned int size_remap;
unsigned int size_total;
+ int request_succeeded = 0;
+
+ printk(KERN_INFO "efifb: probing for efifb\n");
+
+ if (!screen_info.lfb_depth)
+ screen_info.lfb_depth = 32;
+ if (!screen_info.pages)
+ screen_info.pages = 1;
+
+ /* just assume they're all unset if any are */
+ if (!screen_info.blue_size) {
+ screen_info.blue_size = 8;
+ screen_info.blue_pos = 0;
+ screen_info.green_size = 8;
+ screen_info.green_pos = 8;
+ screen_info.red_size = 8;
+ screen_info.red_pos = 16;
+ screen_info.rsvd_size = 8;
+ screen_info.rsvd_pos = 24;
+ }
efifb_fix.smem_start = screen_info.lfb_base;
efifb_defined.bits_per_pixel = screen_info.lfb_depth;
@@ -98,21 +250,25 @@ static int __init efifb_probe(struct platform_device *dev)
* option to simply use size_total as that
* wastes plenty of kernel address space. */
size_remap = size_vmode * 2;
- if (size_remap < size_vmode)
- size_remap = size_vmode;
if (size_remap > size_total)
size_remap = size_total;
+ if (size_remap % PAGE_SIZE)
+ size_remap += PAGE_SIZE - (size_remap % PAGE_SIZE);
efifb_fix.smem_len = size_remap;
- if (!request_mem_region(efifb_fix.smem_start, size_total, "efifb"))
+ if (request_mem_region(efifb_fix.smem_start, size_remap, "efifb")) {
+ request_succeeded = 1;
+ } else {
/* We cannot make this fatal. Sometimes this comes from magic
spaces our resource handlers simply don't know about */
printk(KERN_WARNING
"efifb: cannot reserve video memory at 0x%lx\n",
efifb_fix.smem_start);
+ }
info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
if (!info) {
+ printk(KERN_ERR "efifb: cannot allocate framebuffer\n");
err = -ENOMEM;
goto err_release_mem;
}
@@ -125,7 +281,7 @@ static int __init efifb_probe(struct platform_device *dev)
"0x%x @ 0x%lx\n",
efifb_fix.smem_len, efifb_fix.smem_start);
err = -EIO;
- goto err_unmap;
+ goto err_release_fb;
}
printk(KERN_INFO "efifb: framebuffer at 0x%lx, mapped to 0x%p, "
@@ -178,25 +334,27 @@ static int __init efifb_probe(struct platform_device *dev)
info->fix = efifb_fix;
info->flags = FBINFO_FLAG_DEFAULT;
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
- err = -ENOMEM;
+ if ((err = fb_alloc_cmap(&info->cmap, 256, 0)) < 0) {
+ printk(KERN_ERR "efifb: cannot allocate colormap\n");
goto err_unmap;
}
- if (register_framebuffer(info) < 0) {
- err = -EINVAL;
+ if ((err = register_framebuffer(info)) < 0) {
+ printk(KERN_ERR "efifb: cannot register framebuffer\n");
goto err_fb_dealoc;
}
printk(KERN_INFO "fb%d: %s frame buffer device\n",
- info->node, info->fix.id);
+ info->node, info->fix.id);
return 0;
err_fb_dealoc:
fb_dealloc_cmap(&info->cmap);
err_unmap:
iounmap(info->screen_base);
+err_release_fb:
framebuffer_release(info);
err_release_mem:
- release_mem_region(efifb_fix.smem_start, size_total);
+ if (request_succeeded)
+ release_mem_region(efifb_fix.smem_start, size_total);
return err;
}
@@ -214,9 +372,22 @@ static struct platform_device efifb_device = {
static int __init efifb_init(void)
{
int ret;
+ char *option = NULL;
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI)
return -ENODEV;
+ dmi_check_system(dmi_system_table);
+
+ if (fb_get_options("efifb", &option))
+ return -ENODEV;
+ efifb_setup(option);
+
+ /* We don't get linelength from UGA Draw Protocol, only from
+ * EFI Graphics Protocol. So if it's not in DMI, and it's not
+ * passed in from the user, we really can't use the framebuffer.
+ */
+ if (!screen_info.lfb_linelength)
+ return -ENODEV;
ret = platform_driver_register(&efifb_driver);
diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c
index 6a0aa180c26..5c1a2c01778 100644
--- a/drivers/video/fbmon.c
+++ b/drivers/video/fbmon.c
@@ -564,7 +564,13 @@ static void get_detailed_timing(unsigned char *block,
mode->sync |= FB_SYNC_VERT_HIGH_ACT;
mode->refresh = PIXEL_CLOCK/((H_ACTIVE + H_BLANKING) *
(V_ACTIVE + V_BLANKING));
- mode->vmode = 0;
+ if (INTERLACED) {
+ mode->yres *= 2;
+ mode->upper_margin *= 2;
+ mode->lower_margin *= 2;
+ mode->vsync_len *= 2;
+ mode->vmode |= FB_VMODE_INTERLACED;
+ }
mode->flag = FB_MODE_IS_DETAILED;
DPRINTK(" %d MHz ", PIXEL_CLOCK/1000000);
diff --git a/drivers/video/imacfb.c b/drivers/video/imacfb.c
index 9366ef2bb5f..e69de29bb2d 100644
--- a/drivers/video/imacfb.c
+++ b/drivers/video/imacfb.c
@@ -1,376 +0,0 @@
-/*
- * framebuffer driver for Intel Based Mac's
- *
- * (c) 2006 Edgar Hucek <gimli@dark-green.com>
- * Original imac driver written by Gerd Knorr <kraxel@goldbach.in-berlin.de>
- *
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fb.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/screen_info.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/dmi.h>
-#include <linux/efi.h>
-
-#include <asm/io.h>
-
-#include <video/vga.h>
-
-typedef enum _MAC_TYPE {
- M_I17,
- M_I20,
- M_MINI,
- M_MACBOOK,
- M_UNKNOWN
-} MAC_TYPE;
-
-/* --------------------------------------------------------------------- */
-
-static struct fb_var_screeninfo imacfb_defined __initdata = {
- .activate = FB_ACTIVATE_NOW,
- .height = -1,
- .width = -1,
- .right_margin = 32,
- .upper_margin = 16,
- .lower_margin = 4,
- .vsync_len = 4,
- .vmode = FB_VMODE_NONINTERLACED,
-};
-
-static struct fb_fix_screeninfo imacfb_fix __initdata = {
- .id = "IMAC VGA",
- .type = FB_TYPE_PACKED_PIXELS,
- .accel = FB_ACCEL_NONE,
- .visual = FB_VISUAL_TRUECOLOR,
-};
-
-static int inverse;
-static int model = M_UNKNOWN;
-static int manual_height;
-static int manual_width;
-
-static int set_system(const struct dmi_system_id *id)
-{
- printk(KERN_INFO "imacfb: %s detected - set system to %ld\n",
- id->ident, (long)id->driver_data);
-
- model = (long)id->driver_data;
-
- return 0;
-}
-
-static struct dmi_system_id __initdata dmi_system_table[] = {
- { set_system, "iMac4,1", {
- DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME,"iMac4,1") }, (void*)M_I17},
- { set_system, "MacBookPro1,1", {
- DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBookPro1,1") }, (void*)M_I17},
- { set_system, "MacBook1,1", {
- DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME,"MacBook1,1")}, (void *)M_MACBOOK},
- { set_system, "Macmini1,1", {
- DMI_MATCH(DMI_BIOS_VENDOR,"Apple Computer, Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME,"Macmini1,1")}, (void *)M_MINI},
- {},
-};
-
-#define DEFAULT_FB_MEM 1024*1024*16
-
-/* --------------------------------------------------------------------- */
-
-static int imacfb_setcolreg(unsigned regno, unsigned red, unsigned green,
- unsigned blue, unsigned transp,
- struct fb_info *info)
-{
- /*
- * Set a single color register. The values supplied are
- * already rounded down to the hardware's capabilities
- * (according to the entries in the `var' structure). Return
- * != 0 for invalid regno.
- */
-
- if (regno >= info->cmap.len)
- return 1;
-
- if (regno < 16) {
- red >>= 8;
- green >>= 8;
- blue >>= 8;
- ((u32 *)(info->pseudo_palette))[regno] =
- (red << info->var.red.offset) |
- (green << info->var.green.offset) |
- (blue << info->var.blue.offset);
- }
- return 0;
-}
-
-static struct fb_ops imacfb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = imacfb_setcolreg,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
-};
-
-static int __init imacfb_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!*this_opt) continue;
-
- if (!strcmp(this_opt, "inverse"))
- inverse = 1;
- else if (!strcmp(this_opt, "i17"))
- model = M_I17;
- else if (!strcmp(this_opt, "i20"))
- model = M_I20;
- else if (!strcmp(this_opt, "mini"))
- model = M_MINI;
- else if (!strcmp(this_opt, "macbook"))
- model = M_MACBOOK;
- else if (!strncmp(this_opt, "height:", 7))
- manual_height = simple_strtoul(this_opt+7, NULL, 0);
- else if (!strncmp(this_opt, "width:", 6))
- manual_width = simple_strtoul(this_opt+6, NULL, 0);
- }
- return 0;
-}
-
-static int __init imacfb_probe(struct platform_device *dev)
-{
- struct fb_info *info;
- int err;
- unsigned int size_vmode;
- unsigned int size_remap;
- unsigned int size_total;
-
- screen_info.lfb_depth = 32;
- screen_info.lfb_size = DEFAULT_FB_MEM / 0x10000;
- screen_info.pages=1;
- screen_info.blue_size = 8;
- screen_info.blue_pos = 0;
- screen_info.green_size = 8;
- screen_info.green_pos = 8;
- screen_info.red_size = 8;
- screen_info.red_pos = 16;
- screen_info.rsvd_size = 8;
- screen_info.rsvd_pos = 24;
-
- switch (model) {
- case M_I17:
- screen_info.lfb_width = 1440;
- screen_info.lfb_height = 900;
- screen_info.lfb_linelength = 1472 * 4;
- screen_info.lfb_base = 0x80010000;
- break;
- case M_I20:
- screen_info.lfb_width = 1680;
- screen_info.lfb_height = 1050;
- screen_info.lfb_linelength = 1728 * 4;
- screen_info.lfb_base = 0x80010000;
- break;
- case M_MINI:
- screen_info.lfb_width = 1024;
- screen_info.lfb_height = 768;
- screen_info.lfb_linelength = 2048 * 4;
- screen_info.lfb_base = 0x80000000;
- break;
- case M_MACBOOK:
- screen_info.lfb_width = 1280;
- screen_info.lfb_height = 800;
- screen_info.lfb_linelength = 2048 * 4;
- screen_info.lfb_base = 0x80000000;
- break;
- }
-
- /* if the user wants to manually specify height/width,
- we will override the defaults */
- /* TODO: eventually get auto-detection working */
- if (manual_height > 0)
- screen_info.lfb_height = manual_height;
- if (manual_width > 0)
- screen_info.lfb_width = manual_width;
-
- imacfb_fix.smem_start = screen_info.lfb_base;
- imacfb_defined.bits_per_pixel = screen_info.lfb_depth;
- imacfb_defined.xres = screen_info.lfb_width;
- imacfb_defined.yres = screen_info.lfb_height;
- imacfb_fix.line_length = screen_info.lfb_linelength;
-
- /* size_vmode -- that is the amount of memory needed for the
- * used video mode, i.e. the minimum amount of
- * memory we need. */
- size_vmode = imacfb_defined.yres * imacfb_fix.line_length;
-
- /* size_total -- all video memory we have. Used for
- * entries, ressource allocation and bounds
- * checking. */
- size_total = screen_info.lfb_size * 65536;
- if (size_total < size_vmode)
- size_total = size_vmode;
-
- /* size_remap -- the amount of video memory we are going to
- * use for imacfb. With modern cards it is no
- * option to simply use size_total as that
- * wastes plenty of kernel address space. */
- size_remap = size_vmode * 2;
- if (size_remap < size_vmode)
- size_remap = size_vmode;
- if (size_remap > size_total)
- size_remap = size_total;
- imacfb_fix.smem_len = size_remap;
-
- if (!request_mem_region(imacfb_fix.smem_start, size_total, "imacfb")) {
- printk(KERN_WARNING
- "imacfb: cannot reserve video memory at 0x%lx\n",
- imacfb_fix.smem_start);
- /* We cannot make this fatal. Sometimes this comes from magic
- spaces our resource handlers simply don't know about */
- }
-
- info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev);
- if (!info) {
- err = -ENOMEM;
- goto err_release_mem;
- }
- info->pseudo_palette = info->par;
- info->par = NULL;
-
- info->screen_base = ioremap(imacfb_fix.smem_start, imacfb_fix.smem_len);
- if (!info->screen_base) {
- printk(KERN_ERR "imacfb: abort, cannot ioremap video memory "
- "0x%x @ 0x%lx\n",
- imacfb_fix.smem_len, imacfb_fix.smem_start);
- err = -EIO;
- goto err_unmap;
- }
-
- printk(KERN_INFO "imacfb: framebuffer at 0x%lx, mapped to 0x%p, "
- "using %dk, total %dk\n",
- imacfb_fix.smem_start, info->screen_base,
- size_remap/1024, size_total/1024);
- printk(KERN_INFO "imacfb: mode is %dx%dx%d, linelength=%d, pages=%d\n",
- imacfb_defined.xres, imacfb_defined.yres,
- imacfb_defined.bits_per_pixel, imacfb_fix.line_length,
- screen_info.pages);
-
- imacfb_defined.xres_virtual = imacfb_defined.xres;
- imacfb_defined.yres_virtual = imacfb_fix.smem_len /
- imacfb_fix.line_length;
- printk(KERN_INFO "imacfb: scrolling: redraw\n");
- imacfb_defined.yres_virtual = imacfb_defined.yres;
-
- /* some dummy values for timing to make fbset happy */
- imacfb_defined.pixclock = 10000000 / imacfb_defined.xres *
- 1000 / imacfb_defined.yres;
- imacfb_defined.left_margin = (imacfb_defined.xres / 8) & 0xf8;
- imacfb_defined.hsync_len = (imacfb_defined.xres / 8) & 0xf8;
-
- imacfb_defined.red.offset = screen_info.red_pos;
- imacfb_defined.red.length = screen_info.red_size;
- imacfb_defined.green.offset = screen_info.green_pos;
- imacfb_defined.green.length = screen_info.green_size;
- imacfb_defined.blue.offset = screen_info.blue_pos;
- imacfb_defined.blue.length = screen_info.blue_size;
- imacfb_defined.transp.offset = screen_info.rsvd_pos;
- imacfb_defined.transp.length = screen_info.rsvd_size;
-
- printk(KERN_INFO "imacfb: %s: "
- "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
- "Truecolor",
- screen_info.rsvd_size,
- screen_info.red_size,
- screen_info.green_size,
- screen_info.blue_size,
- screen_info.rsvd_pos,
- screen_info.red_pos,
- screen_info.green_pos,
- screen_info.blue_pos);
-
- imacfb_fix.ypanstep = 0;
- imacfb_fix.ywrapstep = 0;
-
- /* request failure does not faze us, as vgacon probably has this
- * region already (FIXME) */
- request_region(0x3c0, 32, "imacfb");
-
- info->fbops = &imacfb_ops;
- info->var = imacfb_defined;
- info->fix = imacfb_fix;
- info->flags = FBINFO_FLAG_DEFAULT;
-
- if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
- err = -ENOMEM;
- goto err_unmap;
- }
- if (register_framebuffer(info)<0) {
- err = -EINVAL;
- goto err_fb_dealoc;
- }
- printk(KERN_INFO "fb%d: %s frame buffer device\n",
- info->node, info->fix.id);
- return 0;
-
-err_fb_dealoc:
- fb_dealloc_cmap(&info->cmap);
-err_unmap:
- iounmap(info->screen_base);
- framebuffer_release(info);
-err_release_mem:
- release_mem_region(imacfb_fix.smem_start, size_total);
- return err;
-}
-
-static struct platform_driver imacfb_driver = {
- .probe = imacfb_probe,
- .driver = {
- .name = "imacfb",
- },
-};
-
-static struct platform_device imacfb_device = {
- .name = "imacfb",
-};
-
-static int __init imacfb_init(void)
-{
- int ret;
- char *option = NULL;
-
- if (!efi_enabled)
- return -ENODEV;
- if (!dmi_check_system(dmi_system_table))
- return -ENODEV;
- if (model == M_UNKNOWN)
- return -ENODEV;
-
- if (fb_get_options("imacfb", &option))
- return -ENODEV;
-
- imacfb_setup(option);
- ret = platform_driver_register(&imacfb_driver);
-
- if (!ret) {
- ret = platform_device_register(&imacfb_device);
- if (ret)
- platform_driver_unregister(&imacfb_driver);
- }
- return ret;
-}
-module_init(imacfb_init);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index 3325fbd68ab..a50bea61480 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -12,9 +12,9 @@
#endif
/*** Version/name ***/
-#define INTELFB_VERSION "0.9.5"
+#define INTELFB_VERSION "0.9.6"
#define INTELFB_MODULE_NAME "intelfb"
-#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM"
+#define SUPPORTED_CHIPSETS "830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/945GME/965G/965GM"
/*** Debug/feature defines ***/
@@ -58,6 +58,7 @@
#define PCI_DEVICE_ID_INTEL_915GM 0x2592
#define PCI_DEVICE_ID_INTEL_945G 0x2772
#define PCI_DEVICE_ID_INTEL_945GM 0x27A2
+#define PCI_DEVICE_ID_INTEL_945GME 0x27AE
#define PCI_DEVICE_ID_INTEL_965G 0x29A2
#define PCI_DEVICE_ID_INTEL_965GM 0x2A02
@@ -160,6 +161,7 @@ enum intel_chips {
INTEL_915GM,
INTEL_945G,
INTEL_945GM,
+ INTEL_945GME,
INTEL_965G,
INTEL_965GM,
};
@@ -363,6 +365,7 @@ struct intelfb_info {
((dinfo)->chipset == INTEL_915GM) || \
((dinfo)->chipset == INTEL_945G) || \
((dinfo)->chipset == INTEL_945GM) || \
+ ((dinfo)->chipset == INTEL_945GME) || \
((dinfo)->chipset == INTEL_965G) || \
((dinfo)->chipset == INTEL_965GM))
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
index fcf9fadbf57..5d896b81f4e 100644
--- a/drivers/video/intelfb/intelfb_i2c.c
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -171,6 +171,7 @@ void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
/* has some LVDS + tv-out */
case INTEL_945G:
case INTEL_945GM:
+ case INTEL_945GME:
case INTEL_965G:
case INTEL_965GM:
/* SDVO ports have a single control bus - 2 devices */
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index e44303f9bc5..a09e2364935 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -2,7 +2,7 @@
* intelfb
*
* Linux framebuffer driver for Intel(R) 830M/845G/852GM/855GM/865G/915G/915GM/
- * 945G/945GM/965G/965GM integrated graphics chips.
+ * 945G/945GM/945GME/965G/965GM integrated graphics chips.
*
* Copyright © 2002, 2003 David Dawes <dawes@xfree86.org>
* 2004 Sylvain Meyer
@@ -102,6 +102,9 @@
*
* 04/2008 - Version 0.9.5
* Add support for 965G/965GM. (Maik Broemme <mbroemme@plusserver.de>)
+ *
+ * 08/2008 - Version 0.9.6
+ * Add support for 945GME. (Phil Endecott <spam_from_intelfb@chezphil.org>)
*/
#include <linux/module.h>
@@ -183,6 +186,7 @@ static struct pci_device_id intelfb_pci_table[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_915GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_915GM },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GM },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_945GME, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_945GME },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965G, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965G },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_965GM, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA << 8, INTELFB_CLASS_MASK, INTEL_965GM },
{ 0, }
@@ -555,6 +559,7 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
(ent->device == PCI_DEVICE_ID_INTEL_915GM) ||
(ent->device == PCI_DEVICE_ID_INTEL_945G) ||
(ent->device == PCI_DEVICE_ID_INTEL_945GM) ||
+ (ent->device == PCI_DEVICE_ID_INTEL_945GME) ||
(ent->device == PCI_DEVICE_ID_INTEL_965G) ||
(ent->device == PCI_DEVICE_ID_INTEL_965GM)) {
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 8e6d6a4db0a..8b26b27c2db 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -143,6 +143,12 @@ int intelfbhw_get_chipset(struct pci_dev *pdev, struct intelfb_info *dinfo)
dinfo->mobile = 1;
dinfo->pll_index = PLLS_I9xx;
return 0;
+ case PCI_DEVICE_ID_INTEL_945GME:
+ dinfo->name = "Intel(R) 945GME";
+ dinfo->chipset = INTEL_945GME;
+ dinfo->mobile = 1;
+ dinfo->pll_index = PLLS_I9xx;
+ return 0;
case PCI_DEVICE_ID_INTEL_965G:
dinfo->name = "Intel(R) 965G";
dinfo->chipset = INTEL_965G;
@@ -186,6 +192,7 @@ int intelfbhw_get_memory(struct pci_dev *pdev, int *aperture_size,
case PCI_DEVICE_ID_INTEL_915GM:
case PCI_DEVICE_ID_INTEL_945G:
case PCI_DEVICE_ID_INTEL_945GM:
+ case PCI_DEVICE_ID_INTEL_945GME:
case PCI_DEVICE_ID_INTEL_965G:
case PCI_DEVICE_ID_INTEL_965GM:
/* 915, 945 and 965 chipsets support a 256MB aperture.
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index c0213620279..8e7a275df50 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -1453,6 +1453,13 @@ static struct board {
MGA_G100,
&vbG100,
"MGA-G100 (AGP)"},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI, 0xFF,
+ 0, 0,
+ DEVF_G200,
+ 230000,
+ MGA_G200,
+ &vbG200,
+ "MGA-G200eV (PCI)"},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI, 0xFF,
0, 0,
DEVF_G200,
@@ -2118,6 +2125,8 @@ static struct pci_device_id matroxfb_devices[] = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G100_AGP,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200EV_PCI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_PCI,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_G200_AGP,
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index afeed0611e3..df1f757a616 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -188,7 +188,7 @@ static int __devinit load_waveform(u8 *mem, size_t size, int m, int t,
epd_frame_table[par->dt].wfm_size = user_wfm_size;
if (size != epd_frame_table[par->dt].wfm_size) {
- dev_err(dev, "Error: unexpected size %d != %d\n", size,
+ dev_err(dev, "Error: unexpected size %Zd != %d\n", size,
epd_frame_table[par->dt].wfm_size);
return -EINVAL;
}
diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c
index 25172b2a2a9..bfb802d26d5 100644
--- a/drivers/video/neofb.c
+++ b/drivers/video/neofb.c
@@ -426,11 +426,11 @@ static void vgaHWProtect(int on)
{
unsigned char tmp;
+ tmp = vga_rseq(NULL, 0x01);
if (on) {
/*
* Turn off screen and disable sequencer.
*/
- tmp = vga_rseq(NULL, 0x01);
vga_wseq(NULL, 0x00, 0x01); /* Synchronous Reset */
vga_wseq(NULL, 0x01, tmp | 0x20); /* disable the display */
@@ -439,7 +439,6 @@ static void vgaHWProtect(int on)
/*
* Reenable sequencer, then turn on screen.
*/
- tmp = vga_rseq(NULL, 0x01);
vga_wseq(NULL, 0x01, tmp & ~0x20); /* reenable display */
vga_wseq(NULL, 0x00, 0x03); /* clear synchronousreset */
@@ -558,14 +557,12 @@ neofb_open(struct fb_info *info, int user)
{
struct neofb_par *par = info->par;
- mutex_lock(&par->open_lock);
if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_MODE | VGA_SAVE_FONTS;
save_vga(&par->state);
}
par->ref_count++;
- mutex_unlock(&par->open_lock);
return 0;
}
@@ -575,16 +572,13 @@ neofb_release(struct fb_info *info, int user)
{
struct neofb_par *par = info->par;
- mutex_lock(&par->open_lock);
- if (!par->ref_count) {
- mutex_unlock(&par->open_lock);
+ if (!par->ref_count)
return -EINVAL;
- }
+
if (par->ref_count == 1) {
restore_vga(&par->state);
}
par->ref_count--;
- mutex_unlock(&par->open_lock);
return 0;
}
@@ -648,10 +642,10 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
var->blue.msb_right = 0;
var->transp.msb_right = 0;
+ var->transp.offset = 0;
+ var->transp.length = 0;
switch (var->bits_per_pixel) {
case 8: /* PSEUDOCOLOUR, 256 */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 0;
var->red.length = 8;
var->green.offset = 0;
@@ -661,8 +655,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
break;
case 16: /* DIRECTCOLOUR, 64k */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
@@ -672,8 +664,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
break;
case 24: /* TRUECOLOUR, 16m */
- var->transp.offset = 0;
- var->transp.length = 0;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
@@ -704,8 +694,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
if (vramlen > 4 * 1024 * 1024)
vramlen = 4 * 1024 * 1024;
- if (var->yres_virtual < var->yres)
- var->yres_virtual = var->yres;
if (var->xres_virtual < var->xres)
var->xres_virtual = var->xres;
@@ -722,8 +710,6 @@ neofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
if it was possible. We should return -EINVAL, but I disagree */
if (var->yres_virtual < var->yres)
var->yres = var->yres_virtual;
- if (var->xres_virtual < var->xres)
- var->xres = var->xres_virtual;
if (var->xoffset + var->xres > var->xres_virtual)
var->xoffset = var->xres_virtual - var->xres;
if (var->yoffset + var->yres > var->yres_virtual)
@@ -1186,8 +1172,11 @@ static int neofb_set_par(struct fb_info *info)
return 0;
}
-static void neofb_update_start(struct fb_info *info,
- struct fb_var_screeninfo *var)
+/*
+ * Pan or Wrap the Display
+ */
+static int neofb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
{
struct neofb_par *par = info->par;
struct vgastate *state = &par->state;
@@ -1216,35 +1205,7 @@ static void neofb_update_start(struct fb_info *info,
vga_wgfx(state->vgabase, 0x0E, (((Base >> 16) & 0x0f) | (oldExtCRTDispAddr & 0xf0)));
neoLock(state);
-}
-
-/*
- * Pan or Wrap the Display
- */
-static int neofb_pan_display(struct fb_var_screeninfo *var,
- struct fb_info *info)
-{
- u_int y_bottom;
-
- y_bottom = var->yoffset;
-
- if (!(var->vmode & FB_VMODE_YWRAP))
- y_bottom += var->yres;
- if (var->xoffset > (var->xres_virtual - var->xres))
- return -EINVAL;
- if (y_bottom > info->var.yres_virtual)
- return -EINVAL;
-
- neofb_update_start(info, var);
-
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
-
- if (var->vmode & FB_VMODE_YWRAP)
- info->var.vmode |= FB_VMODE_YWRAP;
- else
- info->var.vmode &= ~FB_VMODE_YWRAP;
return 0;
}
@@ -1992,7 +1953,6 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st
info->fix.accel = id->driver_data;
- mutex_init(&par->open_lock);
par->pci_burst = !nopciburst;
par->lcd_stretch = !nostretch;
par->libretto = libretto;
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 6a42c6a0cd9..4c4f7ee6d73 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -32,43 +32,43 @@ static int innovator1610_panel_init(struct lcd_panel *panel,
{
int r = 0;
- if (omap_request_gpio(14)) {
+ if (gpio_request(14, "lcd_en0")) {
pr_err(MODULE_NAME ": can't request GPIO 14\n");
r = -1;
goto exit;
}
- if (omap_request_gpio(15)) {
+ if (gpio_request(15, "lcd_en1")) {
pr_err(MODULE_NAME ": can't request GPIO 15\n");
- omap_free_gpio(14);
+ gpio_free(14);
r = -1;
goto exit;
}
/* configure GPIO(14, 15) as outputs */
- omap_set_gpio_direction(14, 0);
- omap_set_gpio_direction(15, 0);
+ gpio_direction_output(14, 0);
+ gpio_direction_output(15, 0);
exit:
return r;
}
static void innovator1610_panel_cleanup(struct lcd_panel *panel)
{
- omap_free_gpio(15);
- omap_free_gpio(14);
+ gpio_free(15);
+ gpio_free(14);
}
static int innovator1610_panel_enable(struct lcd_panel *panel)
{
/* set GPIO14 and GPIO15 high */
- omap_set_gpio_dataout(14, 1);
- omap_set_gpio_dataout(15, 1);
+ gpio_set_value(14, 1);
+ gpio_set_value(15, 1);
return 0;
}
static void innovator1610_panel_disable(struct lcd_panel *panel)
{
/* set GPIO13, GPIO14 and GPIO15 low */
- omap_set_gpio_dataout(14, 0);
- omap_set_gpio_dataout(15, 0);
+ gpio_set_value(14, 0);
+ gpio_set_value(15, 0);
}
static unsigned long innovator1610_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index a4a725f427a..379c96d36da 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -29,6 +29,7 @@
static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
{
+ /* gpio2 was allocated in board init */
return 0;
}
@@ -47,11 +48,8 @@ static int osk_panel_enable(struct lcd_panel *panel)
/* Set PWL level */
omap_writeb(0xFF, OMAP_PWL_ENABLE);
- /* configure GPIO2 as output */
- omap_set_gpio_direction(2, 0);
-
- /* set GPIO2 high */
- omap_set_gpio_dataout(2, 1);
+ /* set GPIO2 high (lcd power enabled) */
+ gpio_set_value(2, 1);
return 0;
}
@@ -65,7 +63,7 @@ static void osk_panel_disable(struct lcd_panel *panel)
omap_writeb(0x00, OMAP_PWL_CLK_ENABLE);
/* set GPIO2 low */
- omap_set_gpio_dataout(2, 0);
+ gpio_set_value(2, 0);
}
static unsigned long osk_panel_get_caps(struct lcd_panel *panel)
diff --git a/drivers/video/omap/lcd_sx1.c b/drivers/video/omap/lcd_sx1.c
index caa6a896cb8..e55de201b8f 100644
--- a/drivers/video/omap/lcd_sx1.c
+++ b/drivers/video/omap/lcd_sx1.c
@@ -81,21 +81,21 @@ static void epson_sendbyte(int flag, unsigned char byte)
int i, shifter = 0x80;
if (!flag)
- omap_set_gpio_dataout(_A_LCD_SSC_A0, 0);
+ gpio_set_value(_A_LCD_SSC_A0, 0);
mdelay(2);
- omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
+ gpio_set_value(A_LCD_SSC_RD, 1);
- omap_set_gpio_dataout(A_LCD_SSC_SD, flag);
+ gpio_set_value(A_LCD_SSC_SD, flag);
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
for (i = 0; i < 8; i++) {
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2200);
- omap_set_gpio_dataout(A_LCD_SSC_SD, shifter & byte);
+ gpio_set_value(A_LCD_SSC_SD, shifter & byte);
OMAP_MCBSP_WRITE(OMAP1510_MCBSP3_BASE, PCR0, 0x2202);
shifter >>= 1;
}
- omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+ gpio_set_value(_A_LCD_SSC_A0, 1);
}
static void init_system(void)
@@ -107,25 +107,18 @@ static void init_system(void)
static void setup_GPIO(void)
{
/* new wave */
- omap_request_gpio(A_LCD_SSC_RD);
- omap_request_gpio(A_LCD_SSC_SD);
- omap_request_gpio(_A_LCD_RESET);
- omap_request_gpio(_A_LCD_SSC_CS);
- omap_request_gpio(_A_LCD_SSC_A0);
-
- /* set all GPIOs to output */
- omap_set_gpio_direction(A_LCD_SSC_RD, 0);
- omap_set_gpio_direction(A_LCD_SSC_SD, 0);
- omap_set_gpio_direction(_A_LCD_RESET, 0);
- omap_set_gpio_direction(_A_LCD_SSC_CS, 0);
- omap_set_gpio_direction(_A_LCD_SSC_A0, 0);
-
- /* set GPIO data */
- omap_set_gpio_dataout(A_LCD_SSC_RD, 1);
- omap_set_gpio_dataout(A_LCD_SSC_SD, 0);
- omap_set_gpio_dataout(_A_LCD_RESET, 0);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_A0, 1);
+ gpio_request(A_LCD_SSC_RD, "lcd_ssc_rd");
+ gpio_request(A_LCD_SSC_SD, "lcd_ssc_sd");
+ gpio_request(_A_LCD_RESET, "lcd_reset");
+ gpio_request(_A_LCD_SSC_CS, "lcd_ssc_cs");
+ gpio_request(_A_LCD_SSC_A0, "lcd_ssc_a0");
+
+ /* set GPIOs to output, with initial data */
+ gpio_direction_output(A_LCD_SSC_RD, 1);
+ gpio_direction_output(A_LCD_SSC_SD, 0);
+ gpio_direction_output(_A_LCD_RESET, 0);
+ gpio_direction_output(_A_LCD_SSC_CS, 1);
+ gpio_direction_output(_A_LCD_SSC_A0, 1);
}
static void display_init(void)
@@ -139,61 +132,61 @@ static void display_init(void)
mdelay(2);
/* reset LCD */
- omap_set_gpio_dataout(A_LCD_SSC_SD, 1);
+ gpio_set_value(A_LCD_SSC_SD, 1);
epson_sendbyte(0, 0x25);
- omap_set_gpio_dataout(_A_LCD_RESET, 0);
+ gpio_set_value(_A_LCD_RESET, 0);
mdelay(10);
- omap_set_gpio_dataout(_A_LCD_RESET, 1);
+ gpio_set_value(_A_LCD_RESET, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
mdelay(2);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD, phase 1 */
epson_sendbyte(0, 0xCA);
for (i = 0; i < 10; i++)
epson_sendbyte(1, INIT_1[i]);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 2 */
epson_sendbyte(0, 0xCB);
for (i = 0; i < 125; i++)
epson_sendbyte(1, INIT_2[i]);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 2a */
epson_sendbyte(0, 0xCC);
for (i = 0; i < 14; i++)
epson_sendbyte(1, INIT_3[i]);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 3 */
epson_sendbyte(0, 0xBC);
epson_sendbyte(1, 0x08);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 4 */
epson_sendbyte(0, 0x07);
epson_sendbyte(1, 0x05);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 5 */
epson_sendbyte(0, 0x94);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 6 */
epson_sendbyte(0, 0xC6);
epson_sendbyte(1, 0x80);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
mdelay(100); /* used to be 1000 */
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 7 */
epson_sendbyte(0, 0x16);
@@ -201,8 +194,8 @@ static void display_init(void)
epson_sendbyte(1, 0x00);
epson_sendbyte(1, 0xB1);
epson_sendbyte(1, 0x00);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 8 */
epson_sendbyte(0, 0x76);
@@ -210,12 +203,12 @@ static void display_init(void)
epson_sendbyte(1, 0x00);
epson_sendbyte(1, 0xDB);
epson_sendbyte(1, 0x00);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
/* init LCD phase 9 */
epson_sendbyte(0, 0xAF);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
}
static int sx1_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
@@ -231,18 +224,18 @@ static void sx1_panel_disable(struct lcd_panel *panel)
{
printk(KERN_INFO "SX1: LCD panel disable\n");
sx1_setmmipower(0);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
epson_sendbyte(0, 0x25);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
epson_sendbyte(0, 0xAE);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
mdelay(100);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 0);
+ gpio_set_value(_A_LCD_SSC_CS, 0);
epson_sendbyte(0, 0x95);
- omap_set_gpio_dataout(_A_LCD_SSC_CS, 1);
+ gpio_set_value(_A_LCD_SSC_CS, 1);
}
static int sx1_panel_enable(struct lcd_panel *panel)
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index b829dc7c5ed..a7b01d2724b 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -50,6 +50,11 @@
#define dbg(fmt, args...) do { } while (0)
#endif
+static const int __devinitconst s1d13xxxfb_revisions[] = {
+ S1D13506_CHIP_REV, /* Rev.4 on HP Jornada 7xx S1D13506 */
+ S1D13806_CHIP_REV, /* Rev.7 on .. */
+};
+
/*
* Here we define the default struct fb_fix_screeninfo
*/
@@ -538,6 +543,7 @@ s1d13xxxfb_probe(struct platform_device *pdev)
struct fb_info *info;
struct s1d13xxxfb_pdata *pdata = NULL;
int ret = 0;
+ int i;
u8 revision;
dbg("probe called: device is %p\n", pdev);
@@ -607,10 +613,19 @@ s1d13xxxfb_probe(struct platform_device *pdev)
goto bail;
}
- revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE);
- if ((revision >> 2) != S1D_CHIP_REV) {
- printk(KERN_INFO PFX "chip not found: %i\n", (revision >> 2));
- ret = -ENODEV;
+ revision = s1d13xxxfb_readreg(default_par, S1DREG_REV_CODE) >> 2;
+
+ ret = -ENODEV;
+
+ for (i = 0; i < ARRAY_SIZE(s1d13xxxfb_revisions); i++) {
+ if (revision == s1d13xxxfb_revisions[i])
+ ret = 0;
+ }
+
+ if (!ret)
+ printk(KERN_INFO PFX "chip revision %i\n", revision);
+ else {
+ printk(KERN_INFO PFX "unknown chip revision %i\n", revision);
goto bail;
}
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index 4599a4385bc..14bd3f3680b 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -1195,57 +1195,58 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
return -ENOMEM;
default_par = info->par;
+ info->fix = tdfx_fix;
/* Configure the default fb_fix_screeninfo first */
switch (pdev->device) {
case PCI_DEVICE_ID_3DFX_BANSHEE:
- strcpy(tdfx_fix.id, "3Dfx Banshee");
+ strcpy(info->fix.id, "3Dfx Banshee");
default_par->max_pixclock = BANSHEE_MAX_PIXCLOCK;
break;
case PCI_DEVICE_ID_3DFX_VOODOO3:
- strcpy(tdfx_fix.id, "3Dfx Voodoo3");
+ strcpy(info->fix.id, "3Dfx Voodoo3");
default_par->max_pixclock = VOODOO3_MAX_PIXCLOCK;
break;
case PCI_DEVICE_ID_3DFX_VOODOO5:
- strcpy(tdfx_fix.id, "3Dfx Voodoo5");
+ strcpy(info->fix.id, "3Dfx Voodoo5");
default_par->max_pixclock = VOODOO5_MAX_PIXCLOCK;
break;
}
- tdfx_fix.mmio_start = pci_resource_start(pdev, 0);
- tdfx_fix.mmio_len = pci_resource_len(pdev, 0);
- if (!request_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len,
+ info->fix.mmio_start = pci_resource_start(pdev, 0);
+ info->fix.mmio_len = pci_resource_len(pdev, 0);
+ if (!request_mem_region(info->fix.mmio_start, info->fix.mmio_len,
"tdfx regbase")) {
printk(KERN_ERR "tdfxfb: Can't reserve regbase\n");
goto out_err;
}
default_par->regbase_virt =
- ioremap_nocache(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+ ioremap_nocache(info->fix.mmio_start, info->fix.mmio_len);
if (!default_par->regbase_virt) {
printk(KERN_ERR "fb: Can't remap %s register area.\n",
- tdfx_fix.id);
+ info->fix.id);
goto out_err_regbase;
}
- tdfx_fix.smem_start = pci_resource_start(pdev, 1);
- tdfx_fix.smem_len = do_lfb_size(default_par, pdev->device);
- if (!tdfx_fix.smem_len) {
- printk(KERN_ERR "fb: Can't count %s memory.\n", tdfx_fix.id);
+ info->fix.smem_start = pci_resource_start(pdev, 1);
+ info->fix.smem_len = do_lfb_size(default_par, pdev->device);
+ if (!info->fix.smem_len) {
+ printk(KERN_ERR "fb: Can't count %s memory.\n", info->fix.id);
goto out_err_regbase;
}
- if (!request_mem_region(tdfx_fix.smem_start,
+ if (!request_mem_region(info->fix.smem_start,
pci_resource_len(pdev, 1), "tdfx smem")) {
printk(KERN_ERR "tdfxfb: Can't reserve smem\n");
goto out_err_regbase;
}
- info->screen_base = ioremap_nocache(tdfx_fix.smem_start,
- tdfx_fix.smem_len);
+ info->screen_base = ioremap_nocache(info->fix.smem_start,
+ info->fix.smem_len);
if (!info->screen_base) {
printk(KERN_ERR "fb: Can't remap %s framebuffer.\n",
- tdfx_fix.id);
+ info->fix.id);
goto out_err_screenbase;
}
@@ -1257,20 +1258,19 @@ static int __devinit tdfxfb_probe(struct pci_dev *pdev,
goto out_err_screenbase;
}
- printk(KERN_INFO "fb: %s memory = %dK\n", tdfx_fix.id,
- tdfx_fix.smem_len >> 10);
+ printk(KERN_INFO "fb: %s memory = %dK\n", info->fix.id,
+ info->fix.smem_len >> 10);
default_par->mtrr_handle = -1;
if (!nomtrr)
default_par->mtrr_handle =
- mtrr_add(tdfx_fix.smem_start, tdfx_fix.smem_len,
+ mtrr_add(info->fix.smem_start, info->fix.smem_len,
MTRR_TYPE_WRCOMB, 1);
- tdfx_fix.ypanstep = nopan ? 0 : 1;
- tdfx_fix.ywrapstep = nowrap ? 0 : 1;
+ info->fix.ypanstep = nopan ? 0 : 1;
+ info->fix.ywrapstep = nowrap ? 0 : 1;
info->fbops = &tdfxfb_ops;
- info->fix = tdfx_fix;
info->pseudo_palette = default_par->palette;
info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
#ifdef CONFIG_FB_3DFX_ACCEL
@@ -1323,14 +1323,14 @@ out_err_iobase:
out_err_screenbase:
if (info->screen_base)
iounmap(info->screen_base);
- release_mem_region(tdfx_fix.smem_start, pci_resource_len(pdev, 1));
+ release_mem_region(info->fix.smem_start, pci_resource_len(pdev, 1));
out_err_regbase:
/*
* Cleanup after anything that was remapped/allocated.
*/
if (default_par->regbase_virt)
iounmap(default_par->regbase_virt);
- release_mem_region(tdfx_fix.mmio_start, tdfx_fix.mmio_len);
+ release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
out_err:
framebuffer_release(info);
return -ENXIO;
diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
new file mode 100644
index 00000000000..2a380011e9b
--- /dev/null
+++ b/drivers/video/tmiofb.c
@@ -0,0 +1,1050 @@
+/*
+ * Frame Buffer Device for Toshiba Mobile IO(TMIO) controller
+ *
+ * Copyright(C) 2005-2006 Chris Humbert
+ * Copyright(C) 2005 Dirk Opfer
+ * Copytight(C) 2007,2008 Dmitry Baryshkov
+ *
+ * Based on:
+ * drivers/video/w100fb.c
+ * code written by Sharp/Lineo for 2.4 kernels
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+/* Why should fb driver call console functions? because acquire_console_sem() */
+#include <linux/console.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/tmio.h>
+#include <linux/uaccess.h>
+
+/*
+ * accelerator commands
+ */
+#define TMIOFB_ACC_CSADR(x) (0x00000000 | ((x) & 0x001ffffe))
+#define TMIOFB_ACC_CHPIX(x) (0x01000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_CVPIX(x) (0x02000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PSADR(x) (0x03000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_PHPIX(x) (0x04000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PVPIX(x) (0x05000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PHOFS(x) (0x06000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_PVOFS(x) (0x07000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_POADR(x) (0x08000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_RSTR(x) (0x09000000 | ((x) & 0x000000ff))
+#define TMIOFB_ACC_TCLOR(x) (0x0A000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_FILL(x) (0x0B000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_DSADR(x) (0x0C000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_SSADR(x) (0x0D000000 | ((x) & 0x00fffffe))
+#define TMIOFB_ACC_DHPIX(x) (0x0E000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_DVPIX(x) (0x0F000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_SHPIX(x) (0x10000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_SVPIX(x) (0x11000000 | ((x) & 0x000003ff))
+#define TMIOFB_ACC_LBINI(x) (0x12000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_LBK2(x) (0x13000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SHBINI(x) (0x14000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SHBK2(x) (0x15000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SVBINI(x) (0x16000000 | ((x) & 0x0000ffff))
+#define TMIOFB_ACC_SVBK2(x) (0x17000000 | ((x) & 0x0000ffff))
+
+#define TMIOFB_ACC_CMGO 0x20000000
+#define TMIOFB_ACC_CMGO_CEND 0x00000001
+#define TMIOFB_ACC_CMGO_INT 0x00000002
+#define TMIOFB_ACC_CMGO_CMOD 0x00000010
+#define TMIOFB_ACC_CMGO_CDVRV 0x00000020
+#define TMIOFB_ACC_CMGO_CDHRV 0x00000040
+#define TMIOFB_ACC_CMGO_RUND 0x00008000
+#define TMIOFB_ACC_SCGO 0x21000000
+#define TMIOFB_ACC_SCGO_CEND 0x00000001
+#define TMIOFB_ACC_SCGO_INT 0x00000002
+#define TMIOFB_ACC_SCGO_ROP3 0x00000004
+#define TMIOFB_ACC_SCGO_TRNS 0x00000008
+#define TMIOFB_ACC_SCGO_DVRV 0x00000010
+#define TMIOFB_ACC_SCGO_DHRV 0x00000020
+#define TMIOFB_ACC_SCGO_SVRV 0x00000040
+#define TMIOFB_ACC_SCGO_SHRV 0x00000080
+#define TMIOFB_ACC_SCGO_DSTXY 0x00008000
+#define TMIOFB_ACC_SBGO 0x22000000
+#define TMIOFB_ACC_SBGO_CEND 0x00000001
+#define TMIOFB_ACC_SBGO_INT 0x00000002
+#define TMIOFB_ACC_SBGO_DVRV 0x00000010
+#define TMIOFB_ACC_SBGO_DHRV 0x00000020
+#define TMIOFB_ACC_SBGO_SVRV 0x00000040
+#define TMIOFB_ACC_SBGO_SHRV 0x00000080
+#define TMIOFB_ACC_SBGO_SBMD 0x00000100
+#define TMIOFB_ACC_FLGO 0x23000000
+#define TMIOFB_ACC_FLGO_CEND 0x00000001
+#define TMIOFB_ACC_FLGO_INT 0x00000002
+#define TMIOFB_ACC_FLGO_ROP3 0x00000004
+#define TMIOFB_ACC_LDGO 0x24000000
+#define TMIOFB_ACC_LDGO_CEND 0x00000001
+#define TMIOFB_ACC_LDGO_INT 0x00000002
+#define TMIOFB_ACC_LDGO_ROP3 0x00000004
+#define TMIOFB_ACC_LDGO_ENDPX 0x00000008
+#define TMIOFB_ACC_LDGO_LVRV 0x00000010
+#define TMIOFB_ACC_LDGO_LHRV 0x00000020
+#define TMIOFB_ACC_LDGO_LDMOD 0x00000040
+
+/* a FIFO is always allocated, even if acceleration is not used */
+#define TMIOFB_FIFO_SIZE 512
+
+/*
+ * LCD Host Controller Configuration Register
+ *
+ * This iomem area supports only 16-bit IO.
+ */
+#define CCR_CMD 0x04 /* Command */
+#define CCR_REVID 0x08 /* Revision ID */
+#define CCR_BASEL 0x10 /* LCD Control Reg Base Addr Low */
+#define CCR_BASEH 0x12 /* LCD Control Reg Base Addr High */
+#define CCR_UGCC 0x40 /* Unified Gated Clock Control */
+#define CCR_GCC 0x42 /* Gated Clock Control */
+#define CCR_USC 0x50 /* Unified Software Clear */
+#define CCR_VRAMRTC 0x60 /* VRAM Timing Control */
+ /* 0x61 VRAM Refresh Control */
+#define CCR_VRAMSAC 0x62 /* VRAM Access Control */
+ /* 0x63 VRAM Status */
+#define CCR_VRAMBC 0x64 /* VRAM Block Control */
+
+/*
+ * LCD Control Register
+ *
+ * This iomem area supports only 16-bit IO.
+ */
+#define LCR_UIS 0x000 /* Unified Interrupt Status */
+#define LCR_VHPN 0x008 /* VRAM Horizontal Pixel Number */
+#define LCR_CFSAL 0x00a /* Command FIFO Start Address Low */
+#define LCR_CFSAH 0x00c /* Command FIFO Start Address High */
+#define LCR_CFS 0x00e /* Command FIFO Size */
+#define LCR_CFWS 0x010 /* Command FIFO Writeable Size */
+#define LCR_BBIE 0x012 /* BitBLT Interrupt Enable */
+#define LCR_BBISC 0x014 /* BitBLT Interrupt Status and Clear */
+#define LCR_CCS 0x016 /* Command Count Status */
+#define LCR_BBES 0x018 /* BitBLT Execution Status */
+#define LCR_CMDL 0x01c /* Command Low */
+#define LCR_CMDH 0x01e /* Command High */
+#define LCR_CFC 0x022 /* Command FIFO Clear */
+#define LCR_CCIFC 0x024 /* CMOS Camera IF Control */
+#define LCR_HWT 0x026 /* Hardware Test */
+#define LCR_LCDCCRC 0x100 /* LCDC Clock and Reset Control */
+#define LCR_LCDCC 0x102 /* LCDC Control */
+#define LCR_LCDCOPC 0x104 /* LCDC Output Pin Control */
+#define LCR_LCDIS 0x108 /* LCD Interrupt Status */
+#define LCR_LCDIM 0x10a /* LCD Interrupt Mask */
+#define LCR_LCDIE 0x10c /* LCD Interrupt Enable */
+#define LCR_GDSAL 0x122 /* Graphics Display Start Address Low */
+#define LCR_GDSAH 0x124 /* Graphics Display Start Address High */
+#define LCR_VHPCL 0x12a /* VRAM Horizontal Pixel Count Low */
+#define LCR_VHPCH 0x12c /* VRAM Horizontal Pixel Count High */
+#define LCR_GM 0x12e /* Graphic Mode(VRAM access enable) */
+#define LCR_HT 0x140 /* Horizontal Total */
+#define LCR_HDS 0x142 /* Horizontal Display Start */
+#define LCR_HSS 0x144 /* H-Sync Start */
+#define LCR_HSE 0x146 /* H-Sync End */
+#define LCR_HNP 0x14c /* Horizontal Number of Pixels */
+#define LCR_VT 0x150 /* Vertical Total */
+#define LCR_VDS 0x152 /* Vertical Display Start */
+#define LCR_VSS 0x154 /* V-Sync Start */
+#define LCR_VSE 0x156 /* V-Sync End */
+#define LCR_CDLN 0x160 /* Current Display Line Number */
+#define LCR_ILN 0x162 /* Interrupt Line Number */
+#define LCR_SP 0x164 /* Sync Polarity */
+#define LCR_MISC 0x166 /* MISC(RGB565 mode) */
+#define LCR_VIHSS 0x16a /* Video Interface H-Sync Start */
+#define LCR_VIVS 0x16c /* Video Interface Vertical Start */
+#define LCR_VIVE 0x16e /* Video Interface Vertical End */
+#define LCR_VIVSS 0x170 /* Video Interface V-Sync Start */
+#define LCR_VCCIS 0x17e /* Video / CMOS Camera Interface Select */
+#define LCR_VIDWSAL 0x180 /* VI Data Write Start Address Low */
+#define LCR_VIDWSAH 0x182 /* VI Data Write Start Address High */
+#define LCR_VIDRSAL 0x184 /* VI Data Read Start Address Low */
+#define LCR_VIDRSAH 0x186 /* VI Data Read Start Address High */
+#define LCR_VIPDDST 0x188 /* VI Picture Data Display Start Timing */
+#define LCR_VIPDDET 0x186 /* VI Picture Data Display End Timing */
+#define LCR_VIE 0x18c /* Video Interface Enable */
+#define LCR_VCS 0x18e /* Video/Camera Select */
+#define LCR_VPHWC 0x194 /* Video Picture Horizontal Wait Count */
+#define LCR_VPHS 0x196 /* Video Picture Horizontal Size */
+#define LCR_VPVWC 0x198 /* Video Picture Vertical Wait Count */
+#define LCR_VPVS 0x19a /* Video Picture Vertical Size */
+#define LCR_PLHPIX 0x1a0 /* PLHPIX */
+#define LCR_XS 0x1a2 /* XStart */
+#define LCR_XCKHW 0x1a4 /* XCK High Width */
+#define LCR_STHS 0x1a8 /* STH Start */
+#define LCR_VT2 0x1aa /* Vertical Total */
+#define LCR_YCKSW 0x1ac /* YCK Start Wait */
+#define LCR_YSTS 0x1ae /* YST Start */
+#define LCR_PPOLS 0x1b0 /* #PPOL Start */
+#define LCR_PRECW 0x1b2 /* PREC Width */
+#define LCR_VCLKHW 0x1b4 /* VCLK High Width */
+#define LCR_OC 0x1b6 /* Output Control */
+
+static char *mode_option __devinitdata;
+
+struct tmiofb_par {
+ u32 pseudo_palette[16];
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+ wait_queue_head_t wait_acc;
+ bool use_polling;
+#endif
+
+ void __iomem *ccr;
+ void __iomem *lcr;
+};
+
+/*--------------------------------------------------------------------------*/
+
+/*
+ * reasons for an interrupt:
+ * uis bbisc lcdis
+ * 0100 0001 accelerator command completed
+ * 2000 0001 vsync start
+ * 2000 0002 display start
+ * 2000 0004 line number match(0x1ff mask???)
+ */
+static irqreturn_t tmiofb_irq(int irq, void *__info)
+{
+ struct fb_info *info = __info;
+ struct tmiofb_par *par = info->par;
+ unsigned int bbisc = tmio_ioread16(par->lcr + LCR_BBISC);
+
+
+ /*
+ * We were in polling mode and now we got correct irq.
+ * Switch back to IRQ-based sync of command FIFO
+ */
+ if (unlikely(par->use_polling && irq != -1)) {
+ printk(KERN_INFO "tmiofb: switching to waitq\n");
+ par->use_polling = false;
+ }
+
+ tmio_iowrite16(bbisc, par->lcr + LCR_BBISC);
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+ if (bbisc & 1)
+ wake_up(&par->wait_acc);
+#endif
+
+ return IRQ_HANDLED;
+}
+
+
+/*--------------------------------------------------------------------------*/
+
+
+/*
+ * Turns off the LCD controller and LCD host controller.
+ */
+static int tmiofb_hw_stop(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct tmio_fb_data *data = cell->driver_data;
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct tmiofb_par *par = info->par;
+
+ tmio_iowrite16(0, par->ccr + CCR_UGCC);
+ tmio_iowrite16(0, par->lcr + LCR_GM);
+ data->lcd_set_power(dev, 0);
+ tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+
+ return 0;
+}
+
+/*
+ * Initializes the LCD host controller.
+ */
+static int tmiofb_hw_init(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct tmiofb_par *par = info->par;
+ const struct resource *nlcr = &cell->resources[0];
+ const struct resource *vram = &cell->resources[2];
+ unsigned long base;
+
+ if (nlcr == NULL || vram == NULL)
+ return -EINVAL;
+
+ base = nlcr->start;
+
+ tmio_iowrite16(0x003a, par->ccr + CCR_UGCC);
+ tmio_iowrite16(0x003a, par->ccr + CCR_GCC);
+ tmio_iowrite16(0x3f00, par->ccr + CCR_USC);
+
+ msleep(2); /* wait for device to settle */
+
+ tmio_iowrite16(0x0000, par->ccr + CCR_USC);
+ tmio_iowrite16(base >> 16, par->ccr + CCR_BASEH);
+ tmio_iowrite16(base, par->ccr + CCR_BASEL);
+ tmio_iowrite16(0x0002, par->ccr + CCR_CMD); /* base address enable */
+ tmio_iowrite16(0x40a8, par->ccr + CCR_VRAMRTC); /* VRAMRC, VRAMTC */
+ tmio_iowrite16(0x0018, par->ccr + CCR_VRAMSAC); /* VRAMSTS, VRAMAC */
+ tmio_iowrite16(0x0002, par->ccr + CCR_VRAMBC);
+ msleep(2); /* wait for device to settle */
+ tmio_iowrite16(0x000b, par->ccr + CCR_VRAMBC);
+
+ base = vram->start + info->screen_size;
+ tmio_iowrite16(base >> 16, par->lcr + LCR_CFSAH);
+ tmio_iowrite16(base, par->lcr + LCR_CFSAL);
+ tmio_iowrite16(TMIOFB_FIFO_SIZE - 1, par->lcr + LCR_CFS);
+ tmio_iowrite16(1, par->lcr + LCR_CFC);
+ tmio_iowrite16(1, par->lcr + LCR_BBIE);
+ tmio_iowrite16(0, par->lcr + LCR_CFWS);
+
+ return 0;
+}
+
+/*
+ * Sets the LCD controller's output resolution and pixel clock
+ */
+static void tmiofb_hw_mode(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct tmio_fb_data *data = cell->driver_data;
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct fb_videomode *mode = info->mode;
+ struct tmiofb_par *par = info->par;
+ unsigned int i;
+
+ tmio_iowrite16(0, par->lcr + LCR_GM);
+ data->lcd_set_power(dev, 0);
+ tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+ data->lcd_mode(dev, mode);
+ data->lcd_set_power(dev, 1);
+
+ tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPN);
+ tmio_iowrite16(0, par->lcr + LCR_GDSAH);
+ tmio_iowrite16(0, par->lcr + LCR_GDSAL);
+ tmio_iowrite16(info->fix.line_length >> 16, par->lcr + LCR_VHPCH);
+ tmio_iowrite16(info->fix.line_length, par->lcr + LCR_VHPCL);
+ tmio_iowrite16(i = 0, par->lcr + LCR_HSS);
+ tmio_iowrite16(i += mode->hsync_len, par->lcr + LCR_HSE);
+ tmio_iowrite16(i += mode->left_margin, par->lcr + LCR_HDS);
+ tmio_iowrite16(i += mode->xres + mode->right_margin, par->lcr + LCR_HT);
+ tmio_iowrite16(mode->xres, par->lcr + LCR_HNP);
+ tmio_iowrite16(i = 0, par->lcr + LCR_VSS);
+ tmio_iowrite16(i += mode->vsync_len, par->lcr + LCR_VSE);
+ tmio_iowrite16(i += mode->upper_margin, par->lcr + LCR_VDS);
+ tmio_iowrite16(i += mode->yres, par->lcr + LCR_ILN);
+ tmio_iowrite16(i += mode->lower_margin, par->lcr + LCR_VT);
+ tmio_iowrite16(3, par->lcr + LCR_MISC); /* RGB565 mode */
+ tmio_iowrite16(1, par->lcr + LCR_GM); /* VRAM enable */
+ tmio_iowrite16(0x4007, par->lcr + LCR_LCDCC);
+ tmio_iowrite16(3, par->lcr + LCR_SP); /* sync polarity */
+
+ tmio_iowrite16(0x0010, par->lcr + LCR_LCDCCRC);
+ msleep(5); /* wait for device to settle */
+ tmio_iowrite16(0x0014, par->lcr + LCR_LCDCCRC); /* STOP_CKP */
+ msleep(5); /* wait for device to settle */
+ tmio_iowrite16(0x0015, par->lcr + LCR_LCDCCRC); /* STOP_CKP|SOFT_RESET*/
+ tmio_iowrite16(0xfffa, par->lcr + LCR_VCS);
+}
+
+/*--------------------------------------------------------------------------*/
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+static int __must_check
+tmiofb_acc_wait(struct fb_info *info, unsigned int ccs)
+{
+ struct tmiofb_par *par = info->par;
+ /*
+ * This code can be called whith interrupts disabled.
+ * So instead of relaying on irq to trigger the event,
+ * poll the state till the necessary command is executed.
+ */
+ if (irqs_disabled() || par->use_polling) {
+ int i = 0;
+ while (tmio_ioread16(par->lcr + LCR_CCS) > ccs) {
+ udelay(1);
+ i++;
+ if (i > 10000) {
+ pr_err("tmiofb: timeout waiting for %d\n",
+ ccs);
+ return -ETIMEDOUT;
+ }
+ tmiofb_irq(-1, info);
+ }
+ } else {
+ if (!wait_event_interruptible_timeout(par->wait_acc,
+ tmio_ioread16(par->lcr + LCR_CCS) <= ccs,
+ 1000)) {
+ pr_err("tmiofb: timeout waiting for %d\n", ccs);
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Writes an accelerator command to the accelerator's FIFO.
+ */
+static int
+tmiofb_acc_write(struct fb_info *info, const u32 *cmd, unsigned int count)
+{
+ struct tmiofb_par *par = info->par;
+ int ret;
+
+ ret = tmiofb_acc_wait(info, TMIOFB_FIFO_SIZE - count);
+ if (ret)
+ return ret;
+
+ for (; count; count--, cmd++) {
+ tmio_iowrite16(*cmd >> 16, par->lcr + LCR_CMDH);
+ tmio_iowrite16(*cmd, par->lcr + LCR_CMDL);
+ }
+
+ return ret;
+}
+
+/*
+ * Wait for the accelerator to finish its operations before writing
+ * to the framebuffer for consistent display output.
+ */
+static int tmiofb_sync(struct fb_info *fbi)
+{
+ struct tmiofb_par *par = fbi->par;
+
+ int ret;
+ int i = 0;
+
+ ret = tmiofb_acc_wait(fbi, 0);
+
+ while (tmio_ioread16(par->lcr + LCR_BBES) & 2) { /* blit active */
+ udelay(1);
+ i++ ;
+ if (i > 10000) {
+ printk(KERN_ERR "timeout waiting for blit to end!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ return ret;
+}
+
+static void
+tmiofb_fillrect(struct fb_info *fbi, const struct fb_fillrect *rect)
+{
+ const u32 cmd[] = {
+ TMIOFB_ACC_DSADR((rect->dy * fbi->mode->xres + rect->dx) * 2),
+ TMIOFB_ACC_DHPIX(rect->width - 1),
+ TMIOFB_ACC_DVPIX(rect->height - 1),
+ TMIOFB_ACC_FILL(rect->color),
+ TMIOFB_ACC_FLGO,
+ };
+
+ if (fbi->state != FBINFO_STATE_RUNNING ||
+ fbi->flags & FBINFO_HWACCEL_DISABLED) {
+ cfb_fillrect(fbi, rect);
+ return;
+ }
+
+ tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
+}
+
+static void
+tmiofb_copyarea(struct fb_info *fbi, const struct fb_copyarea *area)
+{
+ const u32 cmd[] = {
+ TMIOFB_ACC_DSADR((area->dy * fbi->mode->xres + area->dx) * 2),
+ TMIOFB_ACC_DHPIX(area->width - 1),
+ TMIOFB_ACC_DVPIX(area->height - 1),
+ TMIOFB_ACC_SSADR((area->sy * fbi->mode->xres + area->sx) * 2),
+ TMIOFB_ACC_SCGO,
+ };
+
+ if (fbi->state != FBINFO_STATE_RUNNING ||
+ fbi->flags & FBINFO_HWACCEL_DISABLED) {
+ cfb_copyarea(fbi, area);
+ return;
+ }
+
+ tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
+}
+#endif
+
+static void tmiofb_clearscreen(struct fb_info *info)
+{
+ const struct fb_fillrect rect = {
+ .dx = 0,
+ .dy = 0,
+ .width = info->mode->xres,
+ .height = info->mode->yres,
+ .color = 0,
+ .rop = ROP_COPY,
+ };
+
+ info->fbops->fb_fillrect(info, &rect);
+}
+
+static int tmiofb_vblank(struct fb_info *fbi, struct fb_vblank *vblank)
+{
+ struct tmiofb_par *par = fbi->par;
+ struct fb_videomode *mode = fbi->mode;
+ unsigned int vcount = tmio_ioread16(par->lcr + LCR_CDLN);
+ unsigned int vds = mode->vsync_len + mode->upper_margin;
+
+ vblank->vcount = vcount;
+ vblank->flags = FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT
+ | FB_VBLANK_HAVE_VSYNC;
+
+ if (vcount < mode->vsync_len)
+ vblank->flags |= FB_VBLANK_VSYNCING;
+
+ if (vcount < vds || vcount > vds + mode->yres)
+ vblank->flags |= FB_VBLANK_VBLANKING;
+
+ return 0;
+}
+
+
+static int tmiofb_ioctl(struct fb_info *fbi,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case FBIOGET_VBLANK: {
+ struct fb_vblank vblank = {0};
+ void __user *argp = (void __user *) arg;
+
+ tmiofb_vblank(fbi, &vblank);
+ if (copy_to_user(argp, &vblank, sizeof vblank))
+ return -EFAULT;
+ return 0;
+ }
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+ case FBIO_TMIO_ACC_SYNC:
+ tmiofb_sync(fbi);
+ return 0;
+
+ case FBIO_TMIO_ACC_WRITE: {
+ u32 __user *argp = (void __user *) arg;
+ u32 len;
+ u32 acc[16];
+
+ if (get_user(len, argp))
+ return -EFAULT;
+ if (len > ARRAY_SIZE(acc))
+ return -EINVAL;
+ if (copy_from_user(acc, argp + 1, sizeof(u32) * len))
+ return -EFAULT;
+
+ return tmiofb_acc_write(fbi, acc, len);
+ }
+#endif
+ }
+
+ return -ENOTTY;
+}
+
+/*--------------------------------------------------------------------------*/
+
+/* Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired, the x and y parameters can be rounded up to
+ * match the selected mode.
+ */
+static struct fb_videomode *
+tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
+{
+ struct mfd_cell *cell =
+ info->device->platform_data;
+ struct tmio_fb_data *data = cell->driver_data;
+ struct fb_videomode *best = NULL;
+ int i;
+
+ for (i = 0; i < data->num_modes; i++) {
+ struct fb_videomode *mode = data->modes + i;
+
+ if (mode->xres >= var->xres && mode->yres >= var->yres
+ && (!best || (mode->xres < best->xres
+ && mode->yres < best->yres)))
+ best = mode;
+ }
+
+ return best;
+}
+
+static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+
+ struct fb_videomode *mode;
+ struct mfd_cell *cell =
+ info->device->platform_data;
+ struct tmio_fb_data *data = cell->driver_data;
+
+ mode = tmiofb_find_mode(info, var);
+ if (!mode || var->bits_per_pixel > 16)
+ return -EINVAL;
+
+ fb_videomode_to_var(var, mode);
+
+ var->xres_virtual = mode->xres;
+ var->yres_virtual = info->screen_size / (mode->xres * 2);
+
+ if (var->yres_virtual < var->yres)
+ return -EINVAL;
+
+ var->xoffset = 0;
+ var->yoffset = 0;
+ var->bits_per_pixel = 16;
+ var->grayscale = 0;
+ var->red.offset = 11;
+ var->red.length = 5;
+ var->green.offset = 5;
+ var->green.length = 6;
+ var->blue.offset = 0;
+ var->blue.length = 5;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ var->nonstd = 0;
+ var->height = data->height; /* mm */
+ var->width = data->width; /* mm */
+ var->rotate = 0;
+ return 0;
+}
+
+static int tmiofb_set_par(struct fb_info *info)
+{
+ struct fb_var_screeninfo *var = &info->var;
+ struct fb_videomode *mode;
+
+ mode = tmiofb_find_mode(info, var);
+ if (!mode)
+ return -EINVAL;
+
+ info->mode = mode;
+ info->fix.line_length = info->mode->xres *
+ var->bits_per_pixel / 8;
+
+ tmiofb_hw_mode(to_platform_device(info->device));
+ tmiofb_clearscreen(info);
+ return 0;
+}
+
+static int tmiofb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ struct tmiofb_par *par = info->par;
+
+ if (regno < ARRAY_SIZE(par->pseudo_palette)) {
+ par->pseudo_palette[regno] =
+ ((red & 0xf800)) |
+ ((green & 0xfc00) >> 5) |
+ ((blue & 0xf800) >> 11);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int tmiofb_blank(int blank, struct fb_info *info)
+{
+ /*
+ * everything is done in lcd/bl drivers.
+ * this is purely to make sysfs happy and work.
+ */
+ return 0;
+}
+
+static struct fb_ops tmiofb_ops = {
+ .owner = THIS_MODULE,
+
+ .fb_ioctl = tmiofb_ioctl,
+ .fb_check_var = tmiofb_check_var,
+ .fb_set_par = tmiofb_set_par,
+ .fb_setcolreg = tmiofb_setcolreg,
+ .fb_blank = tmiofb_blank,
+ .fb_imageblit = cfb_imageblit,
+#ifdef CONFIG_FB_TMIO_ACCELL
+ .fb_sync = tmiofb_sync,
+ .fb_fillrect = tmiofb_fillrect,
+ .fb_copyarea = tmiofb_copyarea,
+#else
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+#endif
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __devinit tmiofb_probe(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct tmio_fb_data *data = cell->driver_data;
+ struct resource *ccr = platform_get_resource(dev, IORESOURCE_MEM, 1);
+ struct resource *lcr = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ struct resource *vram = platform_get_resource(dev, IORESOURCE_MEM, 2);
+ int irq = platform_get_irq(dev, 0);
+ struct fb_info *info;
+ struct tmiofb_par *par;
+ int retval;
+
+ /*
+ * This is the only way ATM to disable the fb
+ */
+ if (data == NULL) {
+ dev_err(&dev->dev, "NULL platform data!\n");
+ return -EINVAL;
+ }
+
+ info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev);
+
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+
+#ifdef CONFIG_FB_TMIO_ACCELL
+ init_waitqueue_head(&par->wait_acc);
+
+ par->use_polling = true;
+
+ info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA
+ | FBINFO_HWACCEL_FILLRECT;
+#else
+ info->flags = FBINFO_DEFAULT;
+#endif
+
+ info->fbops = &tmiofb_ops;
+
+ strcpy(info->fix.id, "tmio-fb");
+ info->fix.smem_start = vram->start;
+ info->fix.smem_len = resource_size(vram);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.mmio_start = lcr->start;
+ info->fix.mmio_len = resource_size(lcr);
+ info->fix.accel = FB_ACCEL_NONE;
+ info->screen_size = info->fix.smem_len - (4 * TMIOFB_FIFO_SIZE);
+ info->pseudo_palette = par->pseudo_palette;
+
+ par->ccr = ioremap(ccr->start, resource_size(ccr));
+ if (!par->ccr) {
+ retval = -ENOMEM;
+ goto err_ioremap_ccr;
+ }
+
+ par->lcr = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+ if (!par->lcr) {
+ retval = -ENOMEM;
+ goto err_ioremap_lcr;
+ }
+
+ info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
+ if (!info->screen_base) {
+ retval = -ENOMEM;
+ goto err_ioremap_vram;
+ }
+
+ retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
+ dev->dev.bus_id, info);
+
+ if (retval)
+ goto err_request_irq;
+
+ platform_set_drvdata(dev, info);
+
+ retval = fb_find_mode(&info->var, info, mode_option,
+ data->modes, data->num_modes,
+ data->modes, 16);
+ if (!retval) {
+ retval = -EINVAL;
+ goto err_find_mode;
+ }
+
+ if (cell->enable) {
+ retval = cell->enable(dev);
+ if (retval)
+ goto err_enable;
+ }
+
+ retval = tmiofb_hw_init(dev);
+ if (retval)
+ goto err_hw_init;
+
+ fb_videomode_to_modelist(data->modes, data->num_modes,
+ &info->modelist);
+
+ retval = register_framebuffer(info);
+ if (retval < 0)
+ goto err_register_framebuffer;
+
+ printk(KERN_INFO "fb%d: %s frame buffer device\n",
+ info->node, info->fix.id);
+
+ return 0;
+
+err_register_framebuffer:
+/*err_set_par:*/
+ tmiofb_hw_stop(dev);
+err_hw_init:
+ if (cell->disable)
+ cell->disable(dev);
+err_enable:
+err_find_mode:
+ platform_set_drvdata(dev, NULL);
+ free_irq(irq, info);
+err_request_irq:
+ iounmap(info->screen_base);
+err_ioremap_vram:
+ iounmap(par->lcr);
+err_ioremap_lcr:
+ iounmap(par->ccr);
+err_ioremap_ccr:
+ framebuffer_release(info);
+ return retval;
+}
+
+static int __devexit tmiofb_remove(struct platform_device *dev)
+{
+ struct mfd_cell *cell = dev->dev.platform_data;
+ struct fb_info *info = platform_get_drvdata(dev);
+ int irq = platform_get_irq(dev, 0);
+ struct tmiofb_par *par;
+
+ if (info) {
+ par = info->par;
+ unregister_framebuffer(info);
+
+ tmiofb_hw_stop(dev);
+
+ if (cell->disable)
+ cell->disable(dev);
+
+ platform_set_drvdata(dev, NULL);
+
+ free_irq(irq, info);
+
+ iounmap(info->screen_base);
+ iounmap(par->lcr);
+ iounmap(par->ccr);
+
+ framebuffer_release(info);
+ }
+
+ return 0;
+}
+
+#ifdef DEBUG
+static void tmiofb_dump_regs(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct tmiofb_par *par = info->par;
+
+ printk(KERN_DEBUG "lhccr:\n");
+#define CCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\
+ tmio_ioread16(par->ccr + CCR_ ## n));
+ CCR_PR(CMD);
+ CCR_PR(REVID);
+ CCR_PR(BASEL);
+ CCR_PR(BASEH);
+ CCR_PR(UGCC);
+ CCR_PR(GCC);
+ CCR_PR(USC);
+ CCR_PR(VRAMRTC);
+ CCR_PR(VRAMSAC);
+ CCR_PR(VRAMBC);
+#undef CCR_PR
+
+ printk(KERN_DEBUG "lcr: \n");
+#define LCR_PR(n) printk(KERN_DEBUG "\t" #n " = \t%04x\n",\
+ tmio_ioread16(par->lcr + LCR_ ## n));
+ LCR_PR(UIS);
+ LCR_PR(VHPN);
+ LCR_PR(CFSAL);
+ LCR_PR(CFSAH);
+ LCR_PR(CFS);
+ LCR_PR(CFWS);
+ LCR_PR(BBIE);
+ LCR_PR(BBISC);
+ LCR_PR(CCS);
+ LCR_PR(BBES);
+ LCR_PR(CMDL);
+ LCR_PR(CMDH);
+ LCR_PR(CFC);
+ LCR_PR(CCIFC);
+ LCR_PR(HWT);
+ LCR_PR(LCDCCRC);
+ LCR_PR(LCDCC);
+ LCR_PR(LCDCOPC);
+ LCR_PR(LCDIS);
+ LCR_PR(LCDIM);
+ LCR_PR(LCDIE);
+ LCR_PR(GDSAL);
+ LCR_PR(GDSAH);
+ LCR_PR(VHPCL);
+ LCR_PR(VHPCH);
+ LCR_PR(GM);
+ LCR_PR(HT);
+ LCR_PR(HDS);
+ LCR_PR(HSS);
+ LCR_PR(HSE);
+ LCR_PR(HNP);
+ LCR_PR(VT);
+ LCR_PR(VDS);
+ LCR_PR(VSS);
+ LCR_PR(VSE);
+ LCR_PR(CDLN);
+ LCR_PR(ILN);
+ LCR_PR(SP);
+ LCR_PR(MISC);
+ LCR_PR(VIHSS);
+ LCR_PR(VIVS);
+ LCR_PR(VIVE);
+ LCR_PR(VIVSS);
+ LCR_PR(VCCIS);
+ LCR_PR(VIDWSAL);
+ LCR_PR(VIDWSAH);
+ LCR_PR(VIDRSAL);
+ LCR_PR(VIDRSAH);
+ LCR_PR(VIPDDST);
+ LCR_PR(VIPDDET);
+ LCR_PR(VIE);
+ LCR_PR(VCS);
+ LCR_PR(VPHWC);
+ LCR_PR(VPHS);
+ LCR_PR(VPVWC);
+ LCR_PR(VPVS);
+ LCR_PR(PLHPIX);
+ LCR_PR(XS);
+ LCR_PR(XCKHW);
+ LCR_PR(STHS);
+ LCR_PR(VT2);
+ LCR_PR(YCKSW);
+ LCR_PR(YSTS);
+ LCR_PR(PPOLS);
+ LCR_PR(PRECW);
+ LCR_PR(VCLKHW);
+ LCR_PR(OC);
+#undef LCR_PR
+}
+#endif
+
+#ifdef CONFIG_PM
+static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct tmiofb_par *par = info->par;
+ struct mfd_cell *cell = dev->dev.platform_data;
+ int retval = 0;
+
+ acquire_console_sem();
+
+ fb_set_suspend(info, 1);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+
+ /*
+ * The fb should be usable even if interrupts are disabled (and they are
+ * during suspend/resume). Switch temporary to forced polling.
+ */
+ printk(KERN_INFO "tmiofb: switching to polling\n");
+ par->use_polling = true;
+ tmiofb_hw_stop(dev);
+
+ if (cell->suspend)
+ retval = cell->suspend(dev);
+
+ release_console_sem();
+
+ return retval;
+}
+
+static int tmiofb_resume(struct platform_device *dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct mfd_cell *cell = dev->dev.platform_data;
+ int retval;
+
+ acquire_console_sem();
+
+ if (cell->resume) {
+ retval = cell->resume(dev);
+ if (retval)
+ goto out;
+ }
+
+ tmiofb_irq(-1, info);
+
+ tmiofb_hw_init(dev);
+
+ tmiofb_hw_mode(dev);
+
+ fb_set_suspend(info, 0);
+out:
+ release_console_sem();
+ return retval;
+}
+#else
+#define tmiofb_suspend NULL
+#define tmiofb_resume NULL
+#endif
+
+static struct platform_driver tmiofb_driver = {
+ .driver.name = "tmio-fb",
+ .driver.owner = THIS_MODULE,
+ .probe = tmiofb_probe,
+ .remove = __devexit_p(tmiofb_remove),
+ .suspend = tmiofb_suspend,
+ .resume = tmiofb_resume,
+};
+
+/*--------------------------------------------------------------------------*/
+
+#ifndef MODULE
+static void __init tmiofb_setup(char *options)
+{
+ char *this_opt;
+
+ if (!options || !*options)
+ return;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+ /*
+ * FIXME
+ */
+ }
+}
+#endif
+
+static int __init tmiofb_init(void)
+{
+#ifndef MODULE
+ char *option = NULL;
+
+ if (fb_get_options("tmiofb", &option))
+ return -ENODEV;
+ tmiofb_setup(option);
+#endif
+ return platform_driver_register(&tmiofb_driver);
+}
+
+static void __exit tmiofb_cleanup(void)
+{
+ platform_driver_unregister(&tmiofb_driver);
+}
+
+module_init(tmiofb_init);
+module_exit(tmiofb_cleanup);
+
+MODULE_DESCRIPTION("TMIO framebuffer driver");
+MODULE_AUTHOR("Chris Humbert, Dirk Opfer, Dmitry Baryshkov");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c
index 50744229c7a..6c2d37fdd3b 100644
--- a/drivers/video/uvesafb.c
+++ b/drivers/video/uvesafb.c
@@ -516,10 +516,12 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
err = uvesafb_exec(task);
if (err || (task->t.regs.eax & 0xffff) != 0x004f) {
- printk(KERN_ERR "uvesafb: Getting mode info block "
+ printk(KERN_WARNING "uvesafb: Getting mode info block "
"for mode 0x%x failed (eax=0x%x, err=%d)\n",
*mode, (u32)task->t.regs.eax, err);
- return -EINVAL;
+ mode++;
+ par->vbe_modes_cnt--;
+ continue;
}
mib = task->buf;
@@ -548,7 +550,10 @@ static int __devinit uvesafb_vbe_getmodes(struct uvesafb_ktask *task,
mib->depth = mib->bits_per_pixel;
}
- return 0;
+ if (par->vbe_modes_cnt > 0)
+ return 0;
+ else
+ return -EINVAL;
}
/*
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index e31bca8a0cb..5b2938903ac 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -58,7 +58,6 @@ struct vga16fb_par {
unsigned char ClockingMode; /* Seq-Controller:01h */
} vga_state;
struct vgastate state;
- struct mutex open_lock;
unsigned int ref_count;
int palette_blanked, vesa_blanked, mode, isVGA;
u8 misc, pel_msk, vss, clkdiv;
@@ -286,7 +285,6 @@ static int vga16fb_open(struct fb_info *info, int user)
{
struct vga16fb_par *par = info->par;
- mutex_lock(&par->open_lock);
if (!par->ref_count) {
memset(&par->state, 0, sizeof(struct vgastate));
par->state.flags = VGA_SAVE_FONTS | VGA_SAVE_MODE |
@@ -294,7 +292,6 @@ static int vga16fb_open(struct fb_info *info, int user)
save_vga(&par->state);
}
par->ref_count++;
- mutex_unlock(&par->open_lock);
return 0;
}
@@ -303,15 +300,12 @@ static int vga16fb_release(struct fb_info *info, int user)
{
struct vga16fb_par *par = info->par;
- mutex_lock(&par->open_lock);
- if (!par->ref_count) {
- mutex_unlock(&par->open_lock);
+ if (!par->ref_count)
return -EINVAL;
- }
+
if (par->ref_count == 1)
restore_vga(&par->state);
par->ref_count--;
- mutex_unlock(&par->open_lock);
return 0;
}
@@ -1326,7 +1320,6 @@ static int __init vga16fb_probe(struct platform_device *dev)
printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base);
par = info->par;
- mutex_init(&par->open_lock);
par->isVGA = screen_info.orig_video_isVGA;
par->palette_blanked = 0;
par->vesa_blanked = 0;
diff --git a/drivers/video/via/Makefile b/drivers/video/via/Makefile
new file mode 100644
index 00000000000..e533b4b6aba
--- /dev/null
+++ b/drivers/video/via/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the VIA framebuffer driver (for Linux Kernel 2.6)
+#
+
+obj-$(CONFIG_FB_VIA) += viafb.o
+
+viafb-y :=viafbdev.o hw.o iface.o via_i2c.o dvi.o lcd.o ioctl.o accel.o via_utility.o vt1636.o global.o tblDPASetting.o viamode.o tbl1636.o
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
new file mode 100644
index 00000000000..632523ff1fb
--- /dev/null
+++ b/drivers/video/via/accel.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+void viafb_init_accel(void)
+{
+ viaparinfo->fbmem_free -= CURSOR_SIZE;
+ viaparinfo->cursor_start = viaparinfo->fbmem_free;
+ viaparinfo->fbmem_used += CURSOR_SIZE;
+
+ /* Reverse 8*1024 memory space for cursor image */
+ viaparinfo->fbmem_free -= (CURSOR_SIZE + VQ_SIZE);
+ viaparinfo->VQ_start = viaparinfo->fbmem_free;
+ viaparinfo->VQ_end = viaparinfo->VQ_start + VQ_SIZE - 1;
+ viaparinfo->fbmem_used += (CURSOR_SIZE + VQ_SIZE); }
+
+void viafb_init_2d_engine(void)
+{
+ u32 dwVQStartAddr, dwVQEndAddr;
+ u32 dwVQLen, dwVQStartL, dwVQEndL, dwVQStartEndH;
+
+ /* init 2D engine regs to reset 2D engine */
+ writel(0x0, viaparinfo->io_virt + VIA_REG_GEMODE);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_DSTPOS);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_DIMENSION);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_PATADDR);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_BGCOLOR);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPTL);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CLIPBR);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_OFFSET);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_KEYCONTROL);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_PITCH);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_MONOPAT1);
+
+ /* Init AGP and VQ regs */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ writel(0x00100000, viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+ writel(0x680A0000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(0x02000000, viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ break;
+
+ default:
+ writel(0x00100000, viaparinfo->io_virt + VIA_REG_TRANSET);
+ writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x00333004, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x60000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x61000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x62000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x63000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x64000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x7D000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+ writel(0xFE020000, viaparinfo->io_virt + VIA_REG_TRANSET);
+ writel(0x00000000, viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ break;
+ }
+ if (viaparinfo->VQ_start != 0) {
+ /* Enable VQ */
+ dwVQStartAddr = viaparinfo->VQ_start;
+ dwVQEndAddr = viaparinfo->VQ_end;
+
+ dwVQStartL = 0x50000000 | (dwVQStartAddr & 0xFFFFFF);
+ dwVQEndL = 0x51000000 | (dwVQEndAddr & 0xFFFFFF);
+ dwVQStartEndH = 0x52000000 |
+ ((dwVQStartAddr & 0xFF000000) >> 24) |
+ ((dwVQEndAddr & 0xFF000000) >> 16);
+ dwVQLen = 0x53000000 | (VQ_SIZE >> 3);
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ dwVQStartL |= 0x20000000;
+ dwVQEndL |= 0x20000000;
+ dwVQStartEndH |= 0x20000000;
+ dwVQLen |= 0x20000000;
+ break;
+ default:
+ break;
+ }
+
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ writel(0x00100000,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+ writel(dwVQStartEndH,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(dwVQStartL,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(dwVQEndL,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(dwVQLen,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(0x74301001,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ writel(0x00000000,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ break;
+ default:
+ writel(0x00FE0000,
+ viaparinfo->io_virt + VIA_REG_TRANSET);
+ writel(0x080003FE,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0A00027C,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0B000260,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0C000274,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0D000264,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0E000000,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x0F000020,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x1000027E,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x110002FE,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x200F0060,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+ writel(0x00000006,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x40008C0F,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x44000000,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x45080C04,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x46800408,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+
+ writel(dwVQStartEndH,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(dwVQStartL,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(dwVQEndL,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(dwVQLen,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ break;
+ }
+ } else {
+ /* Disable VQ */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ writel(0x00100000,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSET);
+ writel(0x74301000,
+ viaparinfo->io_virt + VIA_REG_CR_TRANSPACE);
+ break;
+ default:
+ writel(0x00FE0000,
+ viaparinfo->io_virt + VIA_REG_TRANSET);
+ writel(0x00000004,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x40008C0F,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x44000000,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x45080C04,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ writel(0x46800408,
+ viaparinfo->io_virt + VIA_REG_TRANSPACE);
+ break;
+ }
+ }
+
+ viafb_set_2d_color_depth(viaparinfo->bpp);
+
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_DSTBASE);
+
+ writel(VIA_PITCH_ENABLE |
+ (((viaparinfo->hres *
+ viaparinfo->bpp >> 3) >> 3) | (((viaparinfo->hres *
+ viaparinfo->
+ bpp >> 3) >> 3) << 16)),
+ viaparinfo->io_virt + VIA_REG_PITCH);
+}
+
+void viafb_set_2d_color_depth(int bpp)
+{
+ u32 dwGEMode;
+
+ dwGEMode = readl(viaparinfo->io_virt + 0x04) & 0xFFFFFCFF;
+
+ switch (bpp) {
+ case 16:
+ dwGEMode |= VIA_GEM_16bpp;
+ break;
+ case 32:
+ dwGEMode |= VIA_GEM_32bpp;
+ break;
+ default:
+ dwGEMode |= VIA_GEM_8bpp;
+ break;
+ }
+
+ /* Set BPP and Pitch */
+ writel(dwGEMode, viaparinfo->io_virt + VIA_REG_GEMODE);
+}
+
+void viafb_hw_cursor_init(void)
+{
+ /* Set Cursor Image Base Address */
+ writel(viaparinfo->cursor_start,
+ viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_POS);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_ORG);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_BG);
+ writel(0x0, viaparinfo->io_virt + VIA_REG_CURSOR_FG);
+}
+
+void viafb_show_hw_cursor(struct fb_info *info, int Status)
+{
+ u32 temp;
+ u32 iga_path = ((struct viafb_par *)(info->par))->iga_path;
+
+ temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+ switch (Status) {
+ case HW_Cursor_ON:
+ temp |= 0x1;
+ break;
+ case HW_Cursor_OFF:
+ temp &= 0xFFFFFFFE;
+ break;
+ }
+ switch (iga_path) {
+ case IGA2:
+ temp |= 0x80000000;
+ break;
+ case IGA1:
+ default:
+ temp &= 0x7FFFFFFF;
+ }
+ writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+}
+
+int viafb_wait_engine_idle(void)
+{
+ int loop = 0;
+
+ while (!(readl(viaparinfo->io_virt + VIA_REG_STATUS) &
+ VIA_VR_QUEUE_BUSY) && (loop++ < MAXLOOP))
+ cpu_relax();
+
+ while ((readl(viaparinfo->io_virt + VIA_REG_STATUS) &
+ (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY)) &&
+ (loop++ < MAXLOOP))
+ cpu_relax();
+
+ return loop >= MAXLOOP;
+}
diff --git a/drivers/video/via/accel.h b/drivers/video/via/accel.h
new file mode 100644
index 00000000000..29bf854e8cc
--- /dev/null
+++ b/drivers/video/via/accel.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __ACCEL_H__
+#define __ACCEL_H__
+
+#define FB_ACCEL_VIA_UNICHROME 50
+
+/* MMIO Base Address Definition */
+#define MMIO_VGABASE 0x8000
+#define MMIO_CR_READ (MMIO_VGABASE + 0x3D4)
+#define MMIO_CR_WRITE (MMIO_VGABASE + 0x3D5)
+#define MMIO_SR_READ (MMIO_VGABASE + 0x3C4)
+#define MMIO_SR_WRITE (MMIO_VGABASE + 0x3C5)
+
+/* HW Cursor Status Define */
+#define HW_Cursor_ON 0
+#define HW_Cursor_OFF 1
+
+#define CURSOR_SIZE (8 * 1024)
+#define VQ_SIZE (256 * 1024)
+
+#define VIA_MMIO_BLTBASE 0x200000
+#define VIA_MMIO_BLTSIZE 0x200000
+
+/* Defines for 2D registers */
+#define VIA_REG_GECMD 0x000
+#define VIA_REG_GEMODE 0x004
+#define VIA_REG_SRCPOS 0x008
+#define VIA_REG_DSTPOS 0x00C
+/* width and height */
+#define VIA_REG_DIMENSION 0x010
+#define VIA_REG_PATADDR 0x014
+#define VIA_REG_FGCOLOR 0x018
+#define VIA_REG_BGCOLOR 0x01C
+/* top and left of clipping */
+#define VIA_REG_CLIPTL 0x020
+/* bottom and right of clipping */
+#define VIA_REG_CLIPBR 0x024
+#define VIA_REG_OFFSET 0x028
+/* color key control */
+#define VIA_REG_KEYCONTROL 0x02C
+#define VIA_REG_SRCBASE 0x030
+#define VIA_REG_DSTBASE 0x034
+/* pitch of src and dst */
+#define VIA_REG_PITCH 0x038
+#define VIA_REG_MONOPAT0 0x03C
+#define VIA_REG_MONOPAT1 0x040
+/* from 0x100 to 0x1ff */
+#define VIA_REG_COLORPAT 0x100
+
+/* VIA_REG_PITCH(0x38): Pitch Setting */
+#define VIA_PITCH_ENABLE 0x80000000
+
+/* defines for VIA HW cursor registers */
+#define VIA_REG_CURSOR_MODE 0x2D0
+#define VIA_REG_CURSOR_POS 0x2D4
+#define VIA_REG_CURSOR_ORG 0x2D8
+#define VIA_REG_CURSOR_BG 0x2DC
+#define VIA_REG_CURSOR_FG 0x2E0
+
+/* VIA_REG_GEMODE(0x04): GE mode */
+#define VIA_GEM_8bpp 0x00000000
+#define VIA_GEM_16bpp 0x00000100
+#define VIA_GEM_32bpp 0x00000300
+
+/* VIA_REG_GECMD(0x00): 2D Engine Command */
+#define VIA_GEC_NOOP 0x00000000
+#define VIA_GEC_BLT 0x00000001
+#define VIA_GEC_LINE 0x00000005
+
+/* Rotate Command */
+#define VIA_GEC_ROT 0x00000008
+
+#define VIA_GEC_SRC_XY 0x00000000
+#define VIA_GEC_SRC_LINEAR 0x00000010
+#define VIA_GEC_DST_XY 0x00000000
+#define VIA_GEC_DST_LINRAT 0x00000020
+
+#define VIA_GEC_SRC_FB 0x00000000
+#define VIA_GEC_SRC_SYS 0x00000040
+#define VIA_GEC_DST_FB 0x00000000
+#define VIA_GEC_DST_SYS 0x00000080
+
+/* source is mono */
+#define VIA_GEC_SRC_MONO 0x00000100
+/* pattern is mono */
+#define VIA_GEC_PAT_MONO 0x00000200
+/* mono src is opaque */
+#define VIA_GEC_MSRC_OPAQUE 0x00000000
+/* mono src is transparent */
+#define VIA_GEC_MSRC_TRANS 0x00000400
+/* pattern is in frame buffer */
+#define VIA_GEC_PAT_FB 0x00000000
+/* pattern is from reg setting */
+#define VIA_GEC_PAT_REG 0x00000800
+
+#define VIA_GEC_CLIP_DISABLE 0x00000000
+#define VIA_GEC_CLIP_ENABLE 0x00001000
+
+#define VIA_GEC_FIXCOLOR_PAT 0x00002000
+
+#define VIA_GEC_INCX 0x00000000
+#define VIA_GEC_DECY 0x00004000
+#define VIA_GEC_INCY 0x00000000
+#define VIA_GEC_DECX 0x00008000
+/* mono pattern is opaque */
+#define VIA_GEC_MPAT_OPAQUE 0x00000000
+/* mono pattern is transparent */
+#define VIA_GEC_MPAT_TRANS 0x00010000
+
+#define VIA_GEC_MONO_UNPACK 0x00000000
+#define VIA_GEC_MONO_PACK 0x00020000
+#define VIA_GEC_MONO_DWORD 0x00000000
+#define VIA_GEC_MONO_WORD 0x00040000
+#define VIA_GEC_MONO_BYTE 0x00080000
+
+#define VIA_GEC_LASTPIXEL_ON 0x00000000
+#define VIA_GEC_LASTPIXEL_OFF 0x00100000
+#define VIA_GEC_X_MAJOR 0x00000000
+#define VIA_GEC_Y_MAJOR 0x00200000
+#define VIA_GEC_QUICK_START 0x00800000
+
+/* defines for VIA 3D registers */
+#define VIA_REG_STATUS 0x400
+#define VIA_REG_CR_TRANSET 0x41C
+#define VIA_REG_CR_TRANSPACE 0x420
+#define VIA_REG_TRANSET 0x43C
+#define VIA_REG_TRANSPACE 0x440
+
+/* VIA_REG_STATUS(0x400): Engine Status */
+
+/* Command Regulator is busy */
+#define VIA_CMD_RGTR_BUSY 0x00000080
+/* 2D Engine is busy */
+#define VIA_2D_ENG_BUSY 0x00000002
+/* 3D Engine is busy */
+#define VIA_3D_ENG_BUSY 0x00000001
+/* Virtual Queue is busy */
+#define VIA_VR_QUEUE_BUSY 0x00020000
+
+#define MAXLOOP 0xFFFFFF
+
+void viafb_init_accel(void);
+void viafb_init_2d_engine(void);
+void set_2d_color_depth(int);
+void viafb_hw_cursor_init(void);
+void viafb_show_hw_cursor(struct fb_info *info, int Status); int
+viafb_wait_engine_idle(void); void viafb_set_2d_color_depth(int bpp);
+
+#endif /* __ACCEL_H__ */
diff --git a/drivers/video/via/chip.h b/drivers/video/via/chip.h
new file mode 100644
index 00000000000..dde95edc387
--- /dev/null
+++ b/drivers/video/via/chip.h
@@ -0,0 +1,190 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __CHIP_H__
+#define __CHIP_H__
+
+#include "global.h"
+
+/***************************************/
+/* Definition Graphic Chip Information */
+/***************************************/
+
+#define PCI_VIA_VENDOR_ID 0x1106
+
+/* Define VIA Graphic Chip Name */
+#define UNICHROME_CLE266 1
+#define UNICHROME_CLE266_DID 0x3122
+#define CLE266_REVISION_AX 0x0A
+#define CLE266_REVISION_CX 0x0C
+
+#define UNICHROME_K400 2
+#define UNICHROME_K400_DID 0x7205
+
+#define UNICHROME_K800 3
+#define UNICHROME_K800_DID 0x3108
+
+#define UNICHROME_PM800 4
+#define UNICHROME_PM800_DID 0x3118
+
+#define UNICHROME_CN700 5
+#define UNICHROME_CN700_DID 0x3344
+
+#define UNICHROME_CX700 6
+#define UNICHROME_CX700_DID 0x3157
+#define CX700_REVISION_700 0x0
+#define CX700_REVISION_700M 0x1
+#define CX700_REVISION_700M2 0x2
+
+#define UNICHROME_CN750 7
+#define UNICHROME_CN750_DID 0x3225
+
+#define UNICHROME_K8M890 8
+#define UNICHROME_K8M890_DID 0x3230
+
+#define UNICHROME_P4M890 9
+#define UNICHROME_P4M890_DID 0x3343
+
+#define UNICHROME_P4M900 10
+#define UNICHROME_P4M900_DID 0x3371
+
+#define UNICHROME_VX800 11
+#define UNICHROME_VX800_DID 0x1122
+
+/**************************************************/
+/* Definition TMDS Trasmitter Information */
+/**************************************************/
+
+/* Definition TMDS Trasmitter Index */
+#define NON_TMDS_TRANSMITTER 0x00
+#define VT1632_TMDS 0x01
+#define INTEGRATED_TMDS 0x42
+
+/* Definition TMDS Trasmitter I2C Slave Address */
+#define VT1632_TMDS_I2C_ADDR 0x10
+
+/**************************************************/
+/* Definition LVDS Trasmitter Information */
+/**************************************************/
+
+/* Definition LVDS Trasmitter Index */
+#define NON_LVDS_TRANSMITTER 0x00
+#define VT1631_LVDS 0x01
+#define VT1636_LVDS 0x0E
+#define INTEGRATED_LVDS 0x41
+
+/* Definition Digital Transmitter Mode */
+#define TX_DATA_12_BITS 0x01
+#define TX_DATA_24_BITS 0x02
+#define TX_DATA_DDR_MODE 0x04
+#define TX_DATA_SDR_MODE 0x08
+
+/* Definition LVDS Trasmitter I2C Slave Address */
+#define VT1631_LVDS_I2C_ADDR 0x70
+#define VT3271_LVDS_I2C_ADDR 0x80
+#define VT1636_LVDS_I2C_ADDR 0x80
+
+struct tmds_chip_information {
+ int tmds_chip_name;
+ int tmds_chip_slave_addr;
+ int dvi_panel_id;
+ int data_mode;
+ int output_interface;
+ int i2c_port;
+ int device_type;
+};
+
+struct lvds_chip_information {
+ int lvds_chip_name;
+ int lvds_chip_slave_addr;
+ int data_mode;
+ int output_interface;
+ int i2c_port;
+};
+
+struct chip_information {
+ int gfx_chip_name;
+ int gfx_chip_revision;
+ int chip_on_slot;
+ struct tmds_chip_information tmds_chip_info;
+ struct lvds_chip_information lvds_chip_info;
+ struct lvds_chip_information lvds_chip_info2;
+};
+
+struct crt_setting_information {
+ int iga_path;
+ int h_active;
+ int v_active;
+ int bpp;
+ int refresh_rate;
+};
+
+struct tmds_setting_information {
+ int iga_path;
+ int h_active;
+ int v_active;
+ int bpp;
+ int refresh_rate;
+ int get_dvi_size_method;
+ int max_pixel_clock;
+ int dvi_panel_size;
+ int dvi_panel_hres;
+ int dvi_panel_vres;
+ int native_size;
+};
+
+struct lvds_setting_information {
+ int iga_path;
+ int h_active;
+ int v_active;
+ int bpp;
+ int refresh_rate;
+ int get_lcd_size_method;
+ int lcd_panel_id;
+ int lcd_panel_size;
+ int lcd_panel_hres;
+ int lcd_panel_vres;
+ int display_method;
+ int device_lcd_dualedge;
+ int LCDDithering;
+ int lcd_mode;
+ u32 vclk; /*panel mode clock value */
+};
+
+struct GFX_DPA_SETTING {
+ int ClkRangeIndex;
+ u8 DVP0; /* CR96[3:0] */
+ u8 DVP0DataDri_S1; /* SR2A[5] */
+ u8 DVP0DataDri_S; /* SR1B[1] */
+ u8 DVP0ClockDri_S1; /* SR2A[4] */
+ u8 DVP0ClockDri_S; /* SR1E[2] */
+ u8 DVP1; /* CR9B[3:0] */
+ u8 DVP1Driving; /* SR65[3:0], Data and Clock driving */
+ u8 DFPHigh; /* CR97[3:0] */
+ u8 DFPLow; /* CR99[3:0] */
+
+};
+
+struct VT1636_DPA_SETTING {
+ int PanelSizeID;
+ u8 CLK_SEL_ST1;
+ u8 CLK_SEL_ST2;
+};
+#endif /* __CHIP_H__ */
diff --git a/drivers/video/via/debug.h b/drivers/video/via/debug.h
new file mode 100644
index 00000000000..86eacc2017f
--- /dev/null
+++ b/drivers/video/via/debug.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __DEBUG_H__
+#define __DEBUG_H__
+
+#ifndef VIAFB_DEBUG
+#define VIAFB_DEBUG 0
+#endif
+
+#if VIAFB_DEBUG
+#define DEBUG_MSG(f, a...) printk(f, ## a)
+#else
+#define DEBUG_MSG(f, a...)
+#endif
+
+#define VIAFB_WARN 0
+#if VIAFB_WARN
+#define WARN_MSG(f, a...) printk(f, ## a)
+#else
+#define WARN_MSG(f, a...)
+#endif
+
+#endif /* __DEBUG_H__ */
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
new file mode 100644
index 00000000000..d6965447ca6
--- /dev/null
+++ b/drivers/video/via/dvi.c
@@ -0,0 +1,682 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+static void tmds_register_write(int index, u8 data);
+static int tmds_register_read(int index);
+static int tmds_register_read_bytes(int index, u8 *buff, int buff_len);
+static int check_reduce_blanking_mode(int mode_index,
+ int refresh_rate);
+static int dvi_get_panel_size_from_DDCv1(void);
+static int dvi_get_panel_size_from_DDCv2(void);
+static unsigned char dvi_get_panel_info(void);
+static int viafb_dvi_query_EDID(void);
+
+static int check_tmds_chip(int device_id_subaddr, int device_id)
+{
+ if (tmds_register_read(device_id_subaddr) == device_id)
+ return OK;
+ else
+ return FAIL;
+}
+
+void viafb_init_dvi_size(void)
+{
+ DEBUG_MSG(KERN_INFO "viafb_init_dvi_size()\n");
+ DEBUG_MSG(KERN_INFO
+ "viaparinfo->tmds_setting_info->get_dvi_size_method %d\n",
+ viaparinfo->tmds_setting_info->get_dvi_size_method);
+
+ switch (viaparinfo->tmds_setting_info->get_dvi_size_method) {
+ case GET_DVI_SIZE_BY_SYSTEM_BIOS:
+ break;
+ case GET_DVI_SZIE_BY_HW_STRAPPING:
+ break;
+ case GET_DVI_SIZE_BY_VGA_BIOS:
+ default:
+ dvi_get_panel_info();
+ break;
+ }
+ return;
+}
+
+int viafb_tmds_trasmitter_identify(void)
+{
+ unsigned char sr2a = 0, sr1e = 0, sr3e = 0;
+
+ /* Turn on ouputting pad */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ /*=* DFP Low Pad on *=*/
+ sr2a = viafb_read_reg(VIASR, SR2A);
+ viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+ break;
+
+ case UNICHROME_P4M900:
+ case UNICHROME_P4M890:
+ /* DFP Low Pad on */
+ sr2a = viafb_read_reg(VIASR, SR2A);
+ viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+ /* DVP0 Pad on */
+ sr1e = viafb_read_reg(VIASR, SR1E);
+ viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT6 + BIT7);
+ break;
+
+ default:
+ /* DVP0/DVP1 Pad on */
+ sr1e = viafb_read_reg(VIASR, SR1E);
+ viafb_write_reg_mask(SR1E, VIASR, 0xF0, BIT4 +
+ BIT5 + BIT6 + BIT7);
+ /* SR3E[1]Multi-function selection:
+ 0 = Emulate I2C and DDC bus by GPIO2/3/4. */
+ sr3e = viafb_read_reg(VIASR, SR3E);
+ viafb_write_reg_mask(SR3E, VIASR, 0x0, BIT5);
+ break;
+ }
+
+ /* Check for VT1632: */
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = VT1632_TMDS;
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
+ viaparinfo->chip_info->tmds_chip_info.i2c_port = I2CPORTINDEX;
+ if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID) != FAIL) {
+ /*
+ * Currently only support 12bits,dual edge,add 24bits mode later
+ */
+ tmds_register_write(0x08, 0x3b);
+
+ DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->tmds_chip_info.i2c_port);
+ return OK;
+ } else {
+ viaparinfo->chip_info->tmds_chip_info.i2c_port = GPIOPORTINDEX;
+ if (check_tmds_chip(VT1632_DEVICE_ID_REG, VT1632_DEVICE_ID)
+ != FAIL) {
+ tmds_register_write(0x08, 0x3b);
+ DEBUG_MSG(KERN_INFO "\n VT1632 TMDS ! \n");
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_name);
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->
+ tmds_chip_info.i2c_port);
+ return OK;
+ }
+ }
+
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_name = INTEGRATED_TMDS;
+
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) &&
+ ((viafb_display_hardware_layout == HW_LAYOUT_DVI_ONLY) ||
+ (viafb_display_hardware_layout == HW_LAYOUT_LCD_DVI))) {
+ DEBUG_MSG(KERN_INFO "\n Integrated TMDS ! \n");
+ return OK;
+ }
+
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ viafb_write_reg(SR2A, VIASR, sr2a);
+ break;
+
+ case UNICHROME_P4M900:
+ case UNICHROME_P4M890:
+ viafb_write_reg(SR2A, VIASR, sr2a);
+ viafb_write_reg(SR1E, VIASR, sr1e);
+ break;
+
+ default:
+ viafb_write_reg(SR1E, VIASR, sr1e);
+ viafb_write_reg(SR3E, VIASR, sr3e);
+ break;
+ }
+
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_name = NON_TMDS_TRANSMITTER;
+ viaparinfo->chip_info->tmds_chip_info.
+ tmds_chip_slave_addr = VT1632_TMDS_I2C_ADDR;
+ return FAIL;
+}
+
+static void tmds_register_write(int index, u8 data)
+{
+ viaparinfo->i2c_stuff.i2c_port =
+ viaparinfo->chip_info->tmds_chip_info.i2c_port;
+
+ viafb_i2c_writebyte(viaparinfo->chip_info->tmds_chip_info.
+ tmds_chip_slave_addr, index,
+ data);
+}
+
+static int tmds_register_read(int index)
+{
+ u8 data;
+
+ viaparinfo->i2c_stuff.i2c_port =
+ viaparinfo->chip_info->tmds_chip_info.i2c_port;
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_slave_addr,
+ (u8) index, &data);
+ return data;
+}
+
+static int tmds_register_read_bytes(int index, u8 *buff, int buff_len)
+{
+ viaparinfo->i2c_stuff.i2c_port =
+ viaparinfo->chip_info->tmds_chip_info.i2c_port;
+ viafb_i2c_readbytes((u8) viaparinfo->chip_info->tmds_chip_info.
+ tmds_chip_slave_addr, (u8) index, buff, buff_len);
+ return 0;
+}
+
+static int check_reduce_blanking_mode(int mode_index,
+ int refresh_rate)
+{
+ if (refresh_rate != 60)
+ return false;
+
+ switch (mode_index) {
+ /* Following modes have reduce blanking mode. */
+ case VIA_RES_1360X768:
+ case VIA_RES_1400X1050:
+ case VIA_RES_1440X900:
+ case VIA_RES_1600X900:
+ case VIA_RES_1680X1050:
+ case VIA_RES_1920X1080:
+ case VIA_RES_1920X1200:
+ break;
+
+ default:
+ DEBUG_MSG(KERN_INFO
+ "This dvi mode %d have no reduce blanking mode!\n",
+ mode_index);
+ return false;
+ }
+
+ return true;
+}
+
+/* DVI Set Mode */
+void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga)
+{
+ struct VideoModeTable *videoMode = NULL;
+ struct crt_mode_table *pDviTiming;
+ unsigned long desirePixelClock, maxPixelClock;
+ int status = 0;
+ videoMode = viafb_get_modetbl_pointer(video_index);
+ pDviTiming = videoMode->crtc;
+ desirePixelClock = pDviTiming->clk / 1000000;
+ maxPixelClock = (unsigned long)viaparinfo->
+ tmds_setting_info->max_pixel_clock;
+
+ DEBUG_MSG(KERN_INFO "\nDVI_set_mode!!\n");
+
+ if ((maxPixelClock != 0) && (desirePixelClock > maxPixelClock)) {
+ /*Check if reduce-blanking mode is exist */
+ status =
+ check_reduce_blanking_mode(video_index,
+ pDviTiming->refresh_rate);
+ if (status) {
+ video_index += 100; /*Use reduce-blanking mode */
+ videoMode = viafb_get_modetbl_pointer(video_index);
+ pDviTiming = videoMode->crtc;
+ DEBUG_MSG(KERN_INFO
+ "DVI use reduce blanking mode %d!!\n",
+ video_index);
+ }
+ }
+ viafb_fill_crtc_timing(pDviTiming, video_index, mode_bpp / 8, set_iga);
+ viafb_set_output_path(DEVICE_DVI, set_iga,
+ viaparinfo->chip_info->tmds_chip_info.output_interface);
+}
+
+/* Sense DVI Connector */
+int viafb_dvi_sense(void)
+{
+ u8 RegSR1E = 0, RegSR3E = 0, RegCR6B = 0, RegCR91 = 0,
+ RegCR93 = 0, RegCR9B = 0, data;
+ int ret = false;
+
+ DEBUG_MSG(KERN_INFO "viafb_dvi_sense!!\n");
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ /* DI1 Pad on */
+ RegSR1E = viafb_read_reg(VIASR, SR1E);
+ viafb_write_reg(SR1E, VIASR, RegSR1E | 0x30);
+
+ /* CR6B[0]VCK Input Selection: 1 = External clock. */
+ RegCR6B = viafb_read_reg(VIACR, CR6B);
+ viafb_write_reg(CR6B, VIACR, RegCR6B | 0x08);
+
+ /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
+ [0] Software Control Power Sequence */
+ RegCR91 = viafb_read_reg(VIACR, CR91);
+ viafb_write_reg(CR91, VIACR, 0x1D);
+
+ /* CR93[7] DI1 Data Source Selection: 1 = DSP2.
+ CR93[5] DI1 Clock Source: 1 = internal.
+ CR93[4] DI1 Clock Polarity.
+ CR93[3:1] DI1 Clock Adjust. CR93[0] DI1 enable */
+ RegCR93 = viafb_read_reg(VIACR, CR93);
+ viafb_write_reg(CR93, VIACR, 0x01);
+ } else {
+ /* DVP0/DVP1 Pad on */
+ RegSR1E = viafb_read_reg(VIASR, SR1E);
+ viafb_write_reg(SR1E, VIASR, RegSR1E | 0xF0);
+
+ /* SR3E[1]Multi-function selection:
+ 0 = Emulate I2C and DDC bus by GPIO2/3/4. */
+ RegSR3E = viafb_read_reg(VIASR, SR3E);
+ viafb_write_reg(SR3E, VIASR, RegSR3E & (~0x20));
+
+ /* CR91[4] VDD On [3] Data On [2] VEE On [1] Back Light Off
+ [0] Software Control Power Sequence */
+ RegCR91 = viafb_read_reg(VIACR, CR91);
+ viafb_write_reg(CR91, VIACR, 0x1D);
+
+ /*CR9B[4] DVP1 Data Source Selection: 1 = From secondary
+ display.CR9B[2:0] DVP1 Clock Adjust */
+ RegCR9B = viafb_read_reg(VIACR, CR9B);
+ viafb_write_reg(CR9B, VIACR, 0x01);
+ }
+
+ data = (u8) tmds_register_read(0x09);
+ if (data & 0x04)
+ ret = true;
+
+ if (ret == false) {
+ if (viafb_dvi_query_EDID())
+ ret = true;
+ }
+
+ /* Restore status */
+ viafb_write_reg(SR1E, VIASR, RegSR1E);
+ viafb_write_reg(CR91, VIACR, RegCR91);
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ viafb_write_reg(CR6B, VIACR, RegCR6B);
+ viafb_write_reg(CR93, VIACR, RegCR93);
+ } else {
+ viafb_write_reg(SR3E, VIASR, RegSR3E);
+ viafb_write_reg(CR9B, VIACR, RegCR9B);
+ }
+
+ return ret;
+}
+
+/* Query Flat Panel's EDID Table Version Through DVI Connector */
+static int viafb_dvi_query_EDID(void)
+{
+ u8 data0, data1;
+ int restore;
+
+ DEBUG_MSG(KERN_INFO "viafb_dvi_query_EDID!!\n");
+
+ restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
+
+ data0 = (u8) tmds_register_read(0x00);
+ data1 = (u8) tmds_register_read(0x01);
+ if ((data0 == 0) && (data1 == 0xFF)) {
+ viaparinfo->chip_info->
+ tmds_chip_info.tmds_chip_slave_addr = restore;
+ return EDID_VERSION_1; /* Found EDID1 Table */
+ }
+
+ data0 = (u8) tmds_register_read(0x00);
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+ if (data0 == 0x20)
+ return EDID_VERSION_2; /* Found EDID2 Table */
+ else
+ return false;
+}
+
+/*
+ *
+ * int dvi_get_panel_size_from_DDCv1(void)
+ *
+ * - Get Panel Size Using EDID1 Table
+ *
+ * Return Type: int
+ *
+ */
+static int dvi_get_panel_size_from_DDCv1(void)
+{
+ int i, max_h = 0, max_v = 0, tmp, restore;
+ unsigned char rData;
+ unsigned char EDID_DATA[18];
+
+ DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv1 \n");
+
+ restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA0;
+
+ rData = tmds_register_read(0x23);
+ if (rData & 0x3C)
+ max_h = 640;
+ if (rData & 0xC0)
+ max_h = 720;
+ if (rData & 0x03)
+ max_h = 800;
+
+ rData = tmds_register_read(0x24);
+ if (rData & 0xC0)
+ max_h = 800;
+ if (rData & 0x1E)
+ max_h = 1024;
+ if (rData & 0x01)
+ max_h = 1280;
+
+ for (i = 0x25; i < 0x6D; i++) {
+ switch (i) {
+ case 0x26:
+ case 0x28:
+ case 0x2A:
+ case 0x2C:
+ case 0x2E:
+ case 0x30:
+ case 0x32:
+ case 0x34:
+ rData = tmds_register_read(i);
+ if (rData == 1)
+ break;
+ /* data = (data + 31) * 8 */
+ tmp = (rData + 31) << 3;
+ if (tmp > max_h)
+ max_h = tmp;
+ break;
+
+ case 0x36:
+ case 0x48:
+ case 0x5A:
+ case 0x6C:
+ tmds_register_read_bytes(i, EDID_DATA, 10);
+ if (!(EDID_DATA[0] || EDID_DATA[1])) {
+ /* The first two byte must be zero. */
+ if (EDID_DATA[3] == 0xFD) {
+ /* To get max pixel clock. */
+ viaparinfo->tmds_setting_info->
+ max_pixel_clock = EDID_DATA[9] * 10;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch (max_h) {
+ case 640:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_640X480;
+ break;
+ case 800:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_800X600;
+ break;
+ case 1024:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1024X768;
+ break;
+ case 1280:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1280X1024;
+ break;
+ case 1400:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1400X1050;
+ break;
+ case 1440:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1440X1050;
+ break;
+ case 1600:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1600X1200;
+ break;
+ case 1920:
+ if (max_v == 1200) {
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1920X1200;
+ } else {
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1920X1080;
+ }
+
+ break;
+ default:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1024X768;
+ DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d !\
+ set default panel size.\n", max_h);
+ break;
+ }
+
+ DEBUG_MSG(KERN_INFO "DVI max pixelclock = %d\n",
+ viaparinfo->tmds_setting_info->max_pixel_clock);
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+ return viaparinfo->tmds_setting_info->dvi_panel_size;
+}
+
+/*
+ *
+ * int dvi_get_panel_size_from_DDCv2(void)
+ *
+ * - Get Panel Size Using EDID2 Table
+ *
+ * Return Type: int
+ *
+ */
+static int dvi_get_panel_size_from_DDCv2(void)
+{
+ int HSize = 0, restore;
+ unsigned char R_Buffer[2];
+
+ DEBUG_MSG(KERN_INFO "\n dvi_get_panel_size_from_DDCv2 \n");
+
+ restore = viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr;
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = 0xA2;
+
+ /* Horizontal: 0x76, 0x77 */
+ tmds_register_read_bytes(0x76, R_Buffer, 2);
+ HSize = R_Buffer[0];
+ HSize += R_Buffer[1] << 8;
+
+ switch (HSize) {
+ case 640:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_640X480;
+ break;
+ case 800:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_800X600;
+ break;
+ case 1024:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1024X768;
+ break;
+ case 1280:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1280X1024;
+ break;
+ case 1400:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1400X1050;
+ break;
+ case 1440:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1440X1050;
+ break;
+ case 1600:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1600X1200;
+ break;
+ default:
+ viaparinfo->tmds_setting_info->dvi_panel_size =
+ VIA_RES_1024X768;
+ DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d!\
+ set default panel size.\n", HSize);
+ break;
+ }
+
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_slave_addr = restore;
+ return viaparinfo->tmds_setting_info->dvi_panel_size;
+}
+
+/*
+ *
+ * unsigned char dvi_get_panel_info(void)
+ *
+ * - Get Panel Size
+ *
+ * Return Type: unsigned char
+ */
+static unsigned char dvi_get_panel_info(void)
+{
+ unsigned char dvipanelsize;
+ DEBUG_MSG(KERN_INFO "dvi_get_panel_info! \n");
+
+ viafb_dvi_sense();
+ switch (viafb_dvi_query_EDID()) {
+ case 1:
+ dvi_get_panel_size_from_DDCv1();
+ break;
+ case 2:
+ dvi_get_panel_size_from_DDCv2();
+ break;
+ default:
+ break;
+ }
+
+ DEBUG_MSG(KERN_INFO "dvi panel size is %2d \n",
+ viaparinfo->tmds_setting_info->dvi_panel_size);
+ dvipanelsize = (unsigned char)(viaparinfo->
+ tmds_setting_info->dvi_panel_size);
+ return dvipanelsize;
+}
+
+/* If Disable DVI, turn off pad */
+void viafb_dvi_disable(void)
+{
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DVP0)
+ viafb_write_reg(SR1E, VIASR,
+ viafb_read_reg(VIASR, SR1E) & (~0xC0));
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DVP1)
+ viafb_write_reg(SR1E, VIASR,
+ viafb_read_reg(VIASR, SR1E) & (~0x30));
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DFP_HIGH)
+ viafb_write_reg(SR2A, VIASR,
+ viafb_read_reg(VIASR, SR2A) & (~0x0C));
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DFP_LOW)
+ viafb_write_reg(SR2A, VIASR,
+ viafb_read_reg(VIASR, SR2A) & (~0x03));
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_TMDS)
+ /* Turn off TMDS power. */
+ viafb_write_reg(CRD2, VIACR,
+ viafb_read_reg(VIACR, CRD2) | 0x08);
+}
+
+/* If Enable DVI, turn off pad */
+void viafb_dvi_enable(void)
+{
+ u8 data;
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DVP0) {
+ viafb_write_reg(SR1E, VIASR,
+ viafb_read_reg(VIASR, SR1E) | 0xC0);
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ tmds_register_write(0x88, 0x3b);
+ else
+ /*clear CR91[5] to direct on display period
+ in the secondary diplay path */
+ viafb_write_reg(CR91, VIACR,
+ viafb_read_reg(VIACR, CR91) & 0xDF);
+ }
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DVP1) {
+ viafb_write_reg(SR1E, VIASR,
+ viafb_read_reg(VIASR, SR1E) | 0x30);
+
+ /*fix dvi cann't be enabled with MB VT5718C4 - Al Zhang */
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ tmds_register_write(0x88, 0x3b);
+ } else {
+ /*clear CR91[5] to direct on display period
+ in the secondary diplay path */
+ viafb_write_reg(CR91, VIACR,
+ viafb_read_reg(VIACR, CR91) & 0xDF);
+ }
+
+ /*fix DVI cannot enable on EPIA-M board */
+ if (viafb_platform_epia_dvi == 1) {
+ viafb_write_reg_mask(CR91, VIACR, 0x1f, 0x1f);
+ viafb_write_reg_mask(CR88, VIACR, 0x00, BIT6 + BIT0);
+ if (viafb_bus_width == 24) {
+ if (viafb_device_lcd_dualedge == 1)
+ data = 0x3F;
+ else
+ data = 0x37;
+ viafb_i2c_writebyte(viaparinfo->chip_info->
+ tmds_chip_info.
+ tmds_chip_slave_addr,
+ 0x08, data);
+ }
+ }
+ }
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DFP_HIGH) {
+ viafb_write_reg(SR2A, VIASR,
+ viafb_read_reg(VIASR, SR2A) | 0x0C);
+ viafb_write_reg(CR91, VIACR,
+ viafb_read_reg(VIACR, CR91) & 0xDF);
+ }
+
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_DFP_LOW) {
+ viafb_write_reg(SR2A, VIASR,
+ viafb_read_reg(VIASR, SR2A) | 0x03);
+ viafb_write_reg(CR91, VIACR,
+ viafb_read_reg(VIACR, CR91) & 0xDF);
+ }
+ if (viaparinfo->chip_info->
+ tmds_chip_info.output_interface == INTERFACE_TMDS) {
+ /* Turn on Display period in the panel path. */
+ viafb_write_reg_mask(CR91, VIACR, 0, BIT7);
+
+ /* Turn on TMDS power. */
+ viafb_write_reg_mask(CRD2, VIACR, 0, BIT3);
+ }
+}
+
diff --git a/drivers/video/via/dvi.h b/drivers/video/via/dvi.h
new file mode 100644
index 00000000000..e1ec37fb0dc
--- /dev/null
+++ b/drivers/video/via/dvi.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __DVI_H__
+#define __DVI_H__
+
+/*Definition TMDS Device ID register*/
+#define VT1632_DEVICE_ID_REG 0x02
+#define VT1632_DEVICE_ID 0x92
+
+#define GET_DVI_SIZE_BY_SYSTEM_BIOS 0x01
+#define GET_DVI_SIZE_BY_VGA_BIOS 0x02
+#define GET_DVI_SZIE_BY_HW_STRAPPING 0x03
+
+/* Definition DVI Panel ID*/
+/* Resolution: 640x480, Channel: single, Dithering: Enable */
+#define DVI_PANEL_ID0_640X480 0x00
+/* Resolution: 800x600, Channel: single, Dithering: Enable */
+#define DVI_PANEL_ID1_800x600 0x01
+/* Resolution: 1024x768, Channel: single, Dithering: Enable */
+#define DVI_PANEL_ID1_1024x768 0x02
+/* Resolution: 1280x768, Channel: single, Dithering: Enable */
+#define DVI_PANEL_ID1_1280x768 0x03
+/* Resolution: 1280x1024, Channel: dual, Dithering: Enable */
+#define DVI_PANEL_ID1_1280x1024 0x04
+/* Resolution: 1400x1050, Channel: dual, Dithering: Enable */
+#define DVI_PANEL_ID1_1400x1050 0x05
+/* Resolution: 1600x1200, Channel: dual, Dithering: Enable */
+#define DVI_PANEL_ID1_1600x1200 0x06
+
+/* Define the version of EDID*/
+#define EDID_VERSION_1 1
+#define EDID_VERSION_2 2
+
+#define DEV_CONNECT_DVI 0x01
+#define DEV_CONNECT_HDMI 0x02
+
+struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index);
+int viafb_dvi_sense(void);
+void viafb_dvi_disable(void);
+void viafb_dvi_enable(void);
+int viafb_tmds_trasmitter_identify(void);
+void viafb_init_dvi_size(void);
+void viafb_dvi_set_mode(int video_index, int mode_bpp, int set_iga);
+
+#endif /* __DVI_H__ */
diff --git a/drivers/video/via/global.c b/drivers/video/via/global.c
new file mode 100644
index 00000000000..468be2425af
--- /dev/null
+++ b/drivers/video/via/global.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+int viafb_platform_epia_dvi = STATE_OFF;
+int viafb_device_lcd_dualedge = STATE_OFF;
+int viafb_bus_width = 12;
+int viafb_display_hardware_layout = HW_LAYOUT_LCD_DVI;
+int viafb_memsize;
+int viafb_DeviceStatus = CRT_Device;
+int viafb_hotplug;
+int viafb_refresh = 60;
+int viafb_refresh1 = 60;
+int viafb_lcd_dsp_method = LCD_EXPANDSION;
+int viafb_lcd_mode = LCD_OPENLDI;
+int viafb_bpp = 32;
+int viafb_bpp1 = 32;
+int viafb_accel = 1;
+int viafb_CRT_ON = 1;
+int viafb_DVI_ON;
+int viafb_LCD_ON ;
+int viafb_LCD2_ON;
+int viafb_SAMM_ON;
+int viafb_dual_fb;
+int viafb_hotplug_Xres = 640;
+int viafb_hotplug_Yres = 480;
+int viafb_hotplug_bpp = 32;
+int viafb_hotplug_refresh = 60;
+unsigned int viafb_second_offset;
+int viafb_second_size;
+int viafb_primary_dev = None_Device;
+void __iomem *viafb_FB_MM;
+unsigned int viafb_second_xres = 640;
+unsigned int viafb_second_yres = 480;
+unsigned int viafb_second_virtual_xres;
+unsigned int viafb_second_virtual_yres;
+int viafb_lcd_panel_id = LCD_PANEL_ID_MAXIMUM + 1;
+struct fb_cursor viacursor;
+struct fb_info *viafbinfo;
+struct fb_info *viafbinfo1;
+struct viafb_par *viaparinfo;
+struct viafb_par *viaparinfo1;
+
diff --git a/drivers/video/via/global.h b/drivers/video/via/global.h
new file mode 100644
index 00000000000..8e5263c5b81
--- /dev/null
+++ b/drivers/video/via/global.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __GLOBAL_H__
+#define __GLOBAL_H__
+
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/console.h>
+#include <linux/timer.h>
+
+#include "debug.h"
+
+#include "iface.h"
+#include "viafbdev.h"
+#include "chip.h"
+#include "debug.h"
+#include "accel.h"
+#include "share.h"
+#include "dvi.h"
+#include "viamode.h"
+#include "via_i2c.h"
+#include "hw.h"
+
+#include "lcd.h"
+#include "ioctl.h"
+#include "viamode.h"
+#include "via_utility.h"
+#include "vt1636.h"
+#include "tblDPASetting.h"
+#include "tbl1636.h"
+#include "viafbdev.h"
+
+/* External struct*/
+
+extern int viafb_platform_epia_dvi;
+extern int viafb_device_lcd_dualedge;
+extern int viafb_bus_width;
+extern int viafb_display_hardware_layout;
+extern struct offset offset_reg;
+extern struct viafb_par *viaparinfo;
+extern struct viafb_par *viaparinfo1;
+extern struct fb_info *viafbinfo;
+extern struct fb_info *viafbinfo1;
+extern int viafb_DeviceStatus;
+extern int viafb_refresh;
+extern int viafb_refresh1;
+extern int viafb_lcd_dsp_method;
+extern int viafb_lcd_mode;
+extern int viafb_bpp;
+extern int viafb_bpp1;
+
+extern int viafb_CRT_ON;
+extern int viafb_hotplug_Xres;
+extern int viafb_hotplug_Yres;
+extern int viafb_hotplug_bpp;
+extern int viafb_hotplug_refresh;
+extern int viafb_primary_dev;
+extern void __iomem *viafb_FB_MM;
+extern struct fb_cursor viacursor;
+
+extern unsigned int viafb_second_xres;
+extern unsigned int viafb_second_yres;
+extern int viafb_lcd_panel_id;
+
+#endif /* __GLOBAL_H__ */
diff --git a/drivers/video/via/hw.c b/drivers/video/via/hw.c
new file mode 100644
index 00000000000..fcd53ceb88f
--- /dev/null
+++ b/drivers/video/via/hw.c
@@ -0,0 +1,2865 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+static const struct pci_device_id_info pciidlist[] = {
+ {PCI_VIA_VENDOR_ID, UNICHROME_CLE266_DID, UNICHROME_CLE266},
+ {PCI_VIA_VENDOR_ID, UNICHROME_PM800_DID, UNICHROME_PM800},
+ {PCI_VIA_VENDOR_ID, UNICHROME_K400_DID, UNICHROME_K400},
+ {PCI_VIA_VENDOR_ID, UNICHROME_K800_DID, UNICHROME_K800},
+ {PCI_VIA_VENDOR_ID, UNICHROME_CN700_DID, UNICHROME_CN700},
+ {PCI_VIA_VENDOR_ID, UNICHROME_P4M890_DID, UNICHROME_P4M890},
+ {PCI_VIA_VENDOR_ID, UNICHROME_K8M890_DID, UNICHROME_K8M890},
+ {PCI_VIA_VENDOR_ID, UNICHROME_CX700_DID, UNICHROME_CX700},
+ {PCI_VIA_VENDOR_ID, UNICHROME_P4M900_DID, UNICHROME_P4M900},
+ {PCI_VIA_VENDOR_ID, UNICHROME_CN750_DID, UNICHROME_CN750},
+ {PCI_VIA_VENDOR_ID, UNICHROME_VX800_DID, UNICHROME_VX800},
+ {0, 0, 0}
+};
+
+struct offset offset_reg = {
+ /* IGA1 Offset Register */
+ {IGA1_OFFSET_REG_NUM, {{CR13, 0, 7}, {CR35, 5, 7} } },
+ /* IGA2 Offset Register */
+ {IGA2_OFFSET_REG_NUM, {{CR66, 0, 7}, {CR67, 0, 1} } }
+};
+
+static struct pll_map pll_value[] = {
+ {CLK_25_175M, CLE266_PLL_25_175M, K800_PLL_25_175M, CX700_25_175M},
+ {CLK_29_581M, CLE266_PLL_29_581M, K800_PLL_29_581M, CX700_29_581M},
+ {CLK_26_880M, CLE266_PLL_26_880M, K800_PLL_26_880M, CX700_26_880M},
+ {CLK_31_490M, CLE266_PLL_31_490M, K800_PLL_31_490M, CX700_31_490M},
+ {CLK_31_500M, CLE266_PLL_31_500M, K800_PLL_31_500M, CX700_31_500M},
+ {CLK_31_728M, CLE266_PLL_31_728M, K800_PLL_31_728M, CX700_31_728M},
+ {CLK_32_668M, CLE266_PLL_32_668M, K800_PLL_32_668M, CX700_32_668M},
+ {CLK_36_000M, CLE266_PLL_36_000M, K800_PLL_36_000M, CX700_36_000M},
+ {CLK_40_000M, CLE266_PLL_40_000M, K800_PLL_40_000M, CX700_40_000M},
+ {CLK_41_291M, CLE266_PLL_41_291M, K800_PLL_41_291M, CX700_41_291M},
+ {CLK_43_163M, CLE266_PLL_43_163M, K800_PLL_43_163M, CX700_43_163M},
+ {CLK_45_250M, CLE266_PLL_45_250M, K800_PLL_45_250M, CX700_45_250M},
+ {CLK_46_000M, CLE266_PLL_46_000M, K800_PLL_46_000M, CX700_46_000M},
+ {CLK_46_996M, CLE266_PLL_46_996M, K800_PLL_46_996M, CX700_46_996M},
+ {CLK_48_000M, CLE266_PLL_48_000M, K800_PLL_48_000M, CX700_48_000M},
+ {CLK_48_875M, CLE266_PLL_48_875M, K800_PLL_48_875M, CX700_48_875M},
+ {CLK_49_500M, CLE266_PLL_49_500M, K800_PLL_49_500M, CX700_49_500M},
+ {CLK_52_406M, CLE266_PLL_52_406M, K800_PLL_52_406M, CX700_52_406M},
+ {CLK_52_977M, CLE266_PLL_52_977M, K800_PLL_52_977M, CX700_52_977M},
+ {CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M, CX700_56_250M},
+ {CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M, CX700_60_466M},
+ {CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M, CX700_61_500M},
+ {CLK_65_000M, CLE266_PLL_65_000M, K800_PLL_65_000M, CX700_65_000M},
+ {CLK_65_178M, CLE266_PLL_65_178M, K800_PLL_65_178M, CX700_65_178M},
+ {CLK_66_750M, CLE266_PLL_66_750M, K800_PLL_66_750M, CX700_66_750M},
+ {CLK_68_179M, CLE266_PLL_68_179M, K800_PLL_68_179M, CX700_68_179M},
+ {CLK_69_924M, CLE266_PLL_69_924M, K800_PLL_69_924M, CX700_69_924M},
+ {CLK_70_159M, CLE266_PLL_70_159M, K800_PLL_70_159M, CX700_70_159M},
+ {CLK_72_000M, CLE266_PLL_72_000M, K800_PLL_72_000M, CX700_72_000M},
+ {CLK_78_750M, CLE266_PLL_78_750M, K800_PLL_78_750M, CX700_78_750M},
+ {CLK_80_136M, CLE266_PLL_80_136M, K800_PLL_80_136M, CX700_80_136M},
+ {CLK_83_375M, CLE266_PLL_83_375M, K800_PLL_83_375M, CX700_83_375M},
+ {CLK_83_950M, CLE266_PLL_83_950M, K800_PLL_83_950M, CX700_83_950M},
+ {CLK_84_750M, CLE266_PLL_84_750M, K800_PLL_84_750M, CX700_84_750M},
+ {CLK_85_860M, CLE266_PLL_85_860M, K800_PLL_85_860M, CX700_85_860M},
+ {CLK_88_750M, CLE266_PLL_88_750M, K800_PLL_88_750M, CX700_88_750M},
+ {CLK_94_500M, CLE266_PLL_94_500M, K800_PLL_94_500M, CX700_94_500M},
+ {CLK_97_750M, CLE266_PLL_97_750M, K800_PLL_97_750M, CX700_97_750M},
+ {CLK_101_000M, CLE266_PLL_101_000M, K800_PLL_101_000M,
+ CX700_101_000M},
+ {CLK_106_500M, CLE266_PLL_106_500M, K800_PLL_106_500M,
+ CX700_106_500M},
+ {CLK_108_000M, CLE266_PLL_108_000M, K800_PLL_108_000M,
+ CX700_108_000M},
+ {CLK_113_309M, CLE266_PLL_113_309M, K800_PLL_113_309M,
+ CX700_113_309M},
+ {CLK_118_840M, CLE266_PLL_118_840M, K800_PLL_118_840M,
+ CX700_118_840M},
+ {CLK_119_000M, CLE266_PLL_119_000M, K800_PLL_119_000M,
+ CX700_119_000M},
+ {CLK_121_750M, CLE266_PLL_121_750M, K800_PLL_121_750M,
+ CX700_121_750M},
+ {CLK_125_104M, CLE266_PLL_125_104M, K800_PLL_125_104M,
+ CX700_125_104M},
+ {CLK_133_308M, CLE266_PLL_133_308M, K800_PLL_133_308M,
+ CX700_133_308M},
+ {CLK_135_000M, CLE266_PLL_135_000M, K800_PLL_135_000M,
+ CX700_135_000M},
+ {CLK_136_700M, CLE266_PLL_136_700M, K800_PLL_136_700M,
+ CX700_136_700M},
+ {CLK_138_400M, CLE266_PLL_138_400M, K800_PLL_138_400M,
+ CX700_138_400M},
+ {CLK_146_760M, CLE266_PLL_146_760M, K800_PLL_146_760M,
+ CX700_146_760M},
+ {CLK_153_920M, CLE266_PLL_153_920M, K800_PLL_153_920M,
+ CX700_153_920M},
+ {CLK_156_000M, CLE266_PLL_156_000M, K800_PLL_156_000M,
+ CX700_156_000M},
+ {CLK_157_500M, CLE266_PLL_157_500M, K800_PLL_157_500M,
+ CX700_157_500M},
+ {CLK_162_000M, CLE266_PLL_162_000M, K800_PLL_162_000M,
+ CX700_162_000M},
+ {CLK_187_000M, CLE266_PLL_187_000M, K800_PLL_187_000M,
+ CX700_187_000M},
+ {CLK_193_295M, CLE266_PLL_193_295M, K800_PLL_193_295M,
+ CX700_193_295M},
+ {CLK_202_500M, CLE266_PLL_202_500M, K800_PLL_202_500M,
+ CX700_202_500M},
+ {CLK_204_000M, CLE266_PLL_204_000M, K800_PLL_204_000M,
+ CX700_204_000M},
+ {CLK_218_500M, CLE266_PLL_218_500M, K800_PLL_218_500M,
+ CX700_218_500M},
+ {CLK_234_000M, CLE266_PLL_234_000M, K800_PLL_234_000M,
+ CX700_234_000M},
+ {CLK_267_250M, CLE266_PLL_267_250M, K800_PLL_267_250M,
+ CX700_267_250M},
+ {CLK_297_500M, CLE266_PLL_297_500M, K800_PLL_297_500M,
+ CX700_297_500M},
+ {CLK_74_481M, CLE266_PLL_74_481M, K800_PLL_74_481M, CX700_74_481M},
+ {CLK_172_798M, CLE266_PLL_172_798M, K800_PLL_172_798M,
+ CX700_172_798M},
+ {CLK_122_614M, CLE266_PLL_122_614M, K800_PLL_122_614M,
+ CX700_122_614M},
+ {CLK_74_270M, CLE266_PLL_74_270M, K800_PLL_74_270M, CX700_74_270M},
+ {CLK_148_500M, CLE266_PLL_148_500M, K800_PLL_148_500M,
+ CX700_148_500M}
+};
+
+static struct fifo_depth_select display_fifo_depth_reg = {
+ /* IGA1 FIFO Depth_Select */
+ {IGA1_FIFO_DEPTH_SELECT_REG_NUM, {{SR17, 0, 7} } },
+ /* IGA2 FIFO Depth_Select */
+ {IGA2_FIFO_DEPTH_SELECT_REG_NUM,
+ {{CR68, 4, 7}, {CR94, 7, 7}, {CR95, 7, 7} } }
+};
+
+static struct fifo_threshold_select fifo_threshold_select_reg = {
+ /* IGA1 FIFO Threshold Select */
+ {IGA1_FIFO_THRESHOLD_REG_NUM, {{SR16, 0, 5}, {SR16, 7, 7} } },
+ /* IGA2 FIFO Threshold Select */
+ {IGA2_FIFO_THRESHOLD_REG_NUM, {{CR68, 0, 3}, {CR95, 4, 6} } }
+};
+
+static struct fifo_high_threshold_select fifo_high_threshold_select_reg = {
+ /* IGA1 FIFO High Threshold Select */
+ {IGA1_FIFO_HIGH_THRESHOLD_REG_NUM, {{SR18, 0, 5}, {SR18, 7, 7} } },
+ /* IGA2 FIFO High Threshold Select */
+ {IGA2_FIFO_HIGH_THRESHOLD_REG_NUM, {{CR92, 0, 3}, {CR95, 0, 2} } }
+};
+
+static struct display_queue_expire_num display_queue_expire_num_reg = {
+ /* IGA1 Display Queue Expire Num */
+ {IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{SR22, 0, 4} } },
+ /* IGA2 Display Queue Expire Num */
+ {IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM, {{CR94, 0, 6} } }
+};
+
+/* Definition Fetch Count Registers*/
+static struct fetch_count fetch_count_reg = {
+ /* IGA1 Fetch Count Register */
+ {IGA1_FETCH_COUNT_REG_NUM, {{SR1C, 0, 7}, {SR1D, 0, 1} } },
+ /* IGA2 Fetch Count Register */
+ {IGA2_FETCH_COUNT_REG_NUM, {{CR65, 0, 7}, {CR67, 2, 3} } }
+};
+
+static struct iga1_crtc_timing iga1_crtc_reg = {
+ /* IGA1 Horizontal Total */
+ {IGA1_HOR_TOTAL_REG_NUM, {{CR00, 0, 7}, {CR36, 3, 3} } },
+ /* IGA1 Horizontal Addressable Video */
+ {IGA1_HOR_ADDR_REG_NUM, {{CR01, 0, 7} } },
+ /* IGA1 Horizontal Blank Start */
+ {IGA1_HOR_BLANK_START_REG_NUM, {{CR02, 0, 7} } },
+ /* IGA1 Horizontal Blank End */
+ {IGA1_HOR_BLANK_END_REG_NUM,
+ {{CR03, 0, 4}, {CR05, 7, 7}, {CR33, 5, 5} } },
+ /* IGA1 Horizontal Sync Start */
+ {IGA1_HOR_SYNC_START_REG_NUM, {{CR04, 0, 7}, {CR33, 4, 4} } },
+ /* IGA1 Horizontal Sync End */
+ {IGA1_HOR_SYNC_END_REG_NUM, {{CR05, 0, 4} } },
+ /* IGA1 Vertical Total */
+ {IGA1_VER_TOTAL_REG_NUM,
+ {{CR06, 0, 7}, {CR07, 0, 0}, {CR07, 5, 5}, {CR35, 0, 0} } },
+ /* IGA1 Vertical Addressable Video */
+ {IGA1_VER_ADDR_REG_NUM,
+ {{CR12, 0, 7}, {CR07, 1, 1}, {CR07, 6, 6}, {CR35, 2, 2} } },
+ /* IGA1 Vertical Blank Start */
+ {IGA1_VER_BLANK_START_REG_NUM,
+ {{CR15, 0, 7}, {CR07, 3, 3}, {CR09, 5, 5}, {CR35, 3, 3} } },
+ /* IGA1 Vertical Blank End */
+ {IGA1_VER_BLANK_END_REG_NUM, {{CR16, 0, 7} } },
+ /* IGA1 Vertical Sync Start */
+ {IGA1_VER_SYNC_START_REG_NUM,
+ {{CR10, 0, 7}, {CR07, 2, 2}, {CR07, 7, 7}, {CR35, 1, 1} } },
+ /* IGA1 Vertical Sync End */
+ {IGA1_VER_SYNC_END_REG_NUM, {{CR11, 0, 3} } }
+};
+
+static struct iga2_crtc_timing iga2_crtc_reg = {
+ /* IGA2 Horizontal Total */
+ {IGA2_HOR_TOTAL_REG_NUM, {{CR50, 0, 7}, {CR55, 0, 3} } },
+ /* IGA2 Horizontal Addressable Video */
+ {IGA2_HOR_ADDR_REG_NUM, {{CR51, 0, 7}, {CR55, 4, 6} } },
+ /* IGA2 Horizontal Blank Start */
+ {IGA2_HOR_BLANK_START_REG_NUM, {{CR52, 0, 7}, {CR54, 0, 2} } },
+ /* IGA2 Horizontal Blank End */
+ {IGA2_HOR_BLANK_END_REG_NUM,
+ {{CR53, 0, 7}, {CR54, 3, 5}, {CR5D, 6, 6} } },
+ /* IGA2 Horizontal Sync Start */
+ {IGA2_HOR_SYNC_START_REG_NUM,
+ {{CR56, 0, 7}, {CR54, 6, 7}, {CR5C, 7, 7}, {CR5D, 7, 7} } },
+ /* IGA2 Horizontal Sync End */
+ {IGA2_HOR_SYNC_END_REG_NUM, {{CR57, 0, 7}, {CR5C, 6, 6} } },
+ /* IGA2 Vertical Total */
+ {IGA2_VER_TOTAL_REG_NUM, {{CR58, 0, 7}, {CR5D, 0, 2} } },
+ /* IGA2 Vertical Addressable Video */
+ {IGA2_VER_ADDR_REG_NUM, {{CR59, 0, 7}, {CR5D, 3, 5} } },
+ /* IGA2 Vertical Blank Start */
+ {IGA2_VER_BLANK_START_REG_NUM, {{CR5A, 0, 7}, {CR5C, 0, 2} } },
+ /* IGA2 Vertical Blank End */
+ {IGA2_VER_BLANK_END_REG_NUM, {{CR5B, 0, 7}, {CR5C, 3, 5} } },
+ /* IGA2 Vertical Sync Start */
+ {IGA2_VER_SYNC_START_REG_NUM, {{CR5E, 0, 7}, {CR5F, 5, 7} } },
+ /* IGA2 Vertical Sync End */
+ {IGA2_VER_SYNC_END_REG_NUM, {{CR5F, 0, 4} } }
+};
+
+static struct rgbLUT palLUT_table[] = {
+ /* {R,G,B} */
+ /* Index 0x00~0x03 */
+ {0x00, 0x00, 0x00}, {0x00, 0x00, 0x2A}, {0x00, 0x2A, 0x00}, {0x00,
+ 0x2A,
+ 0x2A},
+ /* Index 0x04~0x07 */
+ {0x2A, 0x00, 0x00}, {0x2A, 0x00, 0x2A}, {0x2A, 0x15, 0x00}, {0x2A,
+ 0x2A,
+ 0x2A},
+ /* Index 0x08~0x0B */
+ {0x15, 0x15, 0x15}, {0x15, 0x15, 0x3F}, {0x15, 0x3F, 0x15}, {0x15,
+ 0x3F,
+ 0x3F},
+ /* Index 0x0C~0x0F */
+ {0x3F, 0x15, 0x15}, {0x3F, 0x15, 0x3F}, {0x3F, 0x3F, 0x15}, {0x3F,
+ 0x3F,
+ 0x3F},
+ /* Index 0x10~0x13 */
+ {0x00, 0x00, 0x00}, {0x05, 0x05, 0x05}, {0x08, 0x08, 0x08}, {0x0B,
+ 0x0B,
+ 0x0B},
+ /* Index 0x14~0x17 */
+ {0x0E, 0x0E, 0x0E}, {0x11, 0x11, 0x11}, {0x14, 0x14, 0x14}, {0x18,
+ 0x18,
+ 0x18},
+ /* Index 0x18~0x1B */
+ {0x1C, 0x1C, 0x1C}, {0x20, 0x20, 0x20}, {0x24, 0x24, 0x24}, {0x28,
+ 0x28,
+ 0x28},
+ /* Index 0x1C~0x1F */
+ {0x2D, 0x2D, 0x2D}, {0x32, 0x32, 0x32}, {0x38, 0x38, 0x38}, {0x3F,
+ 0x3F,
+ 0x3F},
+ /* Index 0x20~0x23 */
+ {0x00, 0x00, 0x3F}, {0x10, 0x00, 0x3F}, {0x1F, 0x00, 0x3F}, {0x2F,
+ 0x00,
+ 0x3F},
+ /* Index 0x24~0x27 */
+ {0x3F, 0x00, 0x3F}, {0x3F, 0x00, 0x2F}, {0x3F, 0x00, 0x1F}, {0x3F,
+ 0x00,
+ 0x10},
+ /* Index 0x28~0x2B */
+ {0x3F, 0x00, 0x00}, {0x3F, 0x10, 0x00}, {0x3F, 0x1F, 0x00}, {0x3F,
+ 0x2F,
+ 0x00},
+ /* Index 0x2C~0x2F */
+ {0x3F, 0x3F, 0x00}, {0x2F, 0x3F, 0x00}, {0x1F, 0x3F, 0x00}, {0x10,
+ 0x3F,
+ 0x00},
+ /* Index 0x30~0x33 */
+ {0x00, 0x3F, 0x00}, {0x00, 0x3F, 0x10}, {0x00, 0x3F, 0x1F}, {0x00,
+ 0x3F,
+ 0x2F},
+ /* Index 0x34~0x37 */
+ {0x00, 0x3F, 0x3F}, {0x00, 0x2F, 0x3F}, {0x00, 0x1F, 0x3F}, {0x00,
+ 0x10,
+ 0x3F},
+ /* Index 0x38~0x3B */
+ {0x1F, 0x1F, 0x3F}, {0x27, 0x1F, 0x3F}, {0x2F, 0x1F, 0x3F}, {0x37,
+ 0x1F,
+ 0x3F},
+ /* Index 0x3C~0x3F */
+ {0x3F, 0x1F, 0x3F}, {0x3F, 0x1F, 0x37}, {0x3F, 0x1F, 0x2F}, {0x3F,
+ 0x1F,
+ 0x27},
+ /* Index 0x40~0x43 */
+ {0x3F, 0x1F, 0x1F}, {0x3F, 0x27, 0x1F}, {0x3F, 0x2F, 0x1F}, {0x3F,
+ 0x3F,
+ 0x1F},
+ /* Index 0x44~0x47 */
+ {0x3F, 0x3F, 0x1F}, {0x37, 0x3F, 0x1F}, {0x2F, 0x3F, 0x1F}, {0x27,
+ 0x3F,
+ 0x1F},
+ /* Index 0x48~0x4B */
+ {0x1F, 0x3F, 0x1F}, {0x1F, 0x3F, 0x27}, {0x1F, 0x3F, 0x2F}, {0x1F,
+ 0x3F,
+ 0x37},
+ /* Index 0x4C~0x4F */
+ {0x1F, 0x3F, 0x3F}, {0x1F, 0x37, 0x3F}, {0x1F, 0x2F, 0x3F}, {0x1F,
+ 0x27,
+ 0x3F},
+ /* Index 0x50~0x53 */
+ {0x2D, 0x2D, 0x3F}, {0x31, 0x2D, 0x3F}, {0x36, 0x2D, 0x3F}, {0x3A,
+ 0x2D,
+ 0x3F},
+ /* Index 0x54~0x57 */
+ {0x3F, 0x2D, 0x3F}, {0x3F, 0x2D, 0x3A}, {0x3F, 0x2D, 0x36}, {0x3F,
+ 0x2D,
+ 0x31},
+ /* Index 0x58~0x5B */
+ {0x3F, 0x2D, 0x2D}, {0x3F, 0x31, 0x2D}, {0x3F, 0x36, 0x2D}, {0x3F,
+ 0x3A,
+ 0x2D},
+ /* Index 0x5C~0x5F */
+ {0x3F, 0x3F, 0x2D}, {0x3A, 0x3F, 0x2D}, {0x36, 0x3F, 0x2D}, {0x31,
+ 0x3F,
+ 0x2D},
+ /* Index 0x60~0x63 */
+ {0x2D, 0x3F, 0x2D}, {0x2D, 0x3F, 0x31}, {0x2D, 0x3F, 0x36}, {0x2D,
+ 0x3F,
+ 0x3A},
+ /* Index 0x64~0x67 */
+ {0x2D, 0x3F, 0x3F}, {0x2D, 0x3A, 0x3F}, {0x2D, 0x36, 0x3F}, {0x2D,
+ 0x31,
+ 0x3F},
+ /* Index 0x68~0x6B */
+ {0x00, 0x00, 0x1C}, {0x07, 0x00, 0x1C}, {0x0E, 0x00, 0x1C}, {0x15,
+ 0x00,
+ 0x1C},
+ /* Index 0x6C~0x6F */
+ {0x1C, 0x00, 0x1C}, {0x1C, 0x00, 0x15}, {0x1C, 0x00, 0x0E}, {0x1C,
+ 0x00,
+ 0x07},
+ /* Index 0x70~0x73 */
+ {0x1C, 0x00, 0x00}, {0x1C, 0x07, 0x00}, {0x1C, 0x0E, 0x00}, {0x1C,
+ 0x15,
+ 0x00},
+ /* Index 0x74~0x77 */
+ {0x1C, 0x1C, 0x00}, {0x15, 0x1C, 0x00}, {0x0E, 0x1C, 0x00}, {0x07,
+ 0x1C,
+ 0x00},
+ /* Index 0x78~0x7B */
+ {0x00, 0x1C, 0x00}, {0x00, 0x1C, 0x07}, {0x00, 0x1C, 0x0E}, {0x00,
+ 0x1C,
+ 0x15},
+ /* Index 0x7C~0x7F */
+ {0x00, 0x1C, 0x1C}, {0x00, 0x15, 0x1C}, {0x00, 0x0E, 0x1C}, {0x00,
+ 0x07,
+ 0x1C},
+ /* Index 0x80~0x83 */
+ {0x0E, 0x0E, 0x1C}, {0x11, 0x0E, 0x1C}, {0x15, 0x0E, 0x1C}, {0x18,
+ 0x0E,
+ 0x1C},
+ /* Index 0x84~0x87 */
+ {0x1C, 0x0E, 0x1C}, {0x1C, 0x0E, 0x18}, {0x1C, 0x0E, 0x15}, {0x1C,
+ 0x0E,
+ 0x11},
+ /* Index 0x88~0x8B */
+ {0x1C, 0x0E, 0x0E}, {0x1C, 0x11, 0x0E}, {0x1C, 0x15, 0x0E}, {0x1C,
+ 0x18,
+ 0x0E},
+ /* Index 0x8C~0x8F */
+ {0x1C, 0x1C, 0x0E}, {0x18, 0x1C, 0x0E}, {0x15, 0x1C, 0x0E}, {0x11,
+ 0x1C,
+ 0x0E},
+ /* Index 0x90~0x93 */
+ {0x0E, 0x1C, 0x0E}, {0x0E, 0x1C, 0x11}, {0x0E, 0x1C, 0x15}, {0x0E,
+ 0x1C,
+ 0x18},
+ /* Index 0x94~0x97 */
+ {0x0E, 0x1C, 0x1C}, {0x0E, 0x18, 0x1C}, {0x0E, 0x15, 0x1C}, {0x0E,
+ 0x11,
+ 0x1C},
+ /* Index 0x98~0x9B */
+ {0x14, 0x14, 0x1C}, {0x16, 0x14, 0x1C}, {0x18, 0x14, 0x1C}, {0x1A,
+ 0x14,
+ 0x1C},
+ /* Index 0x9C~0x9F */
+ {0x1C, 0x14, 0x1C}, {0x1C, 0x14, 0x1A}, {0x1C, 0x14, 0x18}, {0x1C,
+ 0x14,
+ 0x16},
+ /* Index 0xA0~0xA3 */
+ {0x1C, 0x14, 0x14}, {0x1C, 0x16, 0x14}, {0x1C, 0x18, 0x14}, {0x1C,
+ 0x1A,
+ 0x14},
+ /* Index 0xA4~0xA7 */
+ {0x1C, 0x1C, 0x14}, {0x1A, 0x1C, 0x14}, {0x18, 0x1C, 0x14}, {0x16,
+ 0x1C,
+ 0x14},
+ /* Index 0xA8~0xAB */
+ {0x14, 0x1C, 0x14}, {0x14, 0x1C, 0x16}, {0x14, 0x1C, 0x18}, {0x14,
+ 0x1C,
+ 0x1A},
+ /* Index 0xAC~0xAF */
+ {0x14, 0x1C, 0x1C}, {0x14, 0x1A, 0x1C}, {0x14, 0x18, 0x1C}, {0x14,
+ 0x16,
+ 0x1C},
+ /* Index 0xB0~0xB3 */
+ {0x00, 0x00, 0x10}, {0x04, 0x00, 0x10}, {0x08, 0x00, 0x10}, {0x0C,
+ 0x00,
+ 0x10},
+ /* Index 0xB4~0xB7 */
+ {0x10, 0x00, 0x10}, {0x10, 0x00, 0x0C}, {0x10, 0x00, 0x08}, {0x10,
+ 0x00,
+ 0x04},
+ /* Index 0xB8~0xBB */
+ {0x10, 0x00, 0x00}, {0x10, 0x04, 0x00}, {0x10, 0x08, 0x00}, {0x10,
+ 0x0C,
+ 0x00},
+ /* Index 0xBC~0xBF */
+ {0x10, 0x10, 0x00}, {0x0C, 0x10, 0x00}, {0x08, 0x10, 0x00}, {0x04,
+ 0x10,
+ 0x00},
+ /* Index 0xC0~0xC3 */
+ {0x00, 0x10, 0x00}, {0x00, 0x10, 0x04}, {0x00, 0x10, 0x08}, {0x00,
+ 0x10,
+ 0x0C},
+ /* Index 0xC4~0xC7 */
+ {0x00, 0x10, 0x10}, {0x00, 0x0C, 0x10}, {0x00, 0x08, 0x10}, {0x00,
+ 0x04,
+ 0x10},
+ /* Index 0xC8~0xCB */
+ {0x08, 0x08, 0x10}, {0x0A, 0x08, 0x10}, {0x0C, 0x08, 0x10}, {0x0E,
+ 0x08,
+ 0x10},
+ /* Index 0xCC~0xCF */
+ {0x10, 0x08, 0x10}, {0x10, 0x08, 0x0E}, {0x10, 0x08, 0x0C}, {0x10,
+ 0x08,
+ 0x0A},
+ /* Index 0xD0~0xD3 */
+ {0x10, 0x08, 0x08}, {0x10, 0x0A, 0x08}, {0x10, 0x0C, 0x08}, {0x10,
+ 0x0E,
+ 0x08},
+ /* Index 0xD4~0xD7 */
+ {0x10, 0x10, 0x08}, {0x0E, 0x10, 0x08}, {0x0C, 0x10, 0x08}, {0x0A,
+ 0x10,
+ 0x08},
+ /* Index 0xD8~0xDB */
+ {0x08, 0x10, 0x08}, {0x08, 0x10, 0x0A}, {0x08, 0x10, 0x0C}, {0x08,
+ 0x10,
+ 0x0E},
+ /* Index 0xDC~0xDF */
+ {0x08, 0x10, 0x10}, {0x08, 0x0E, 0x10}, {0x08, 0x0C, 0x10}, {0x08,
+ 0x0A,
+ 0x10},
+ /* Index 0xE0~0xE3 */
+ {0x0B, 0x0B, 0x10}, {0x0C, 0x0B, 0x10}, {0x0D, 0x0B, 0x10}, {0x0F,
+ 0x0B,
+ 0x10},
+ /* Index 0xE4~0xE7 */
+ {0x10, 0x0B, 0x10}, {0x10, 0x0B, 0x0F}, {0x10, 0x0B, 0x0D}, {0x10,
+ 0x0B,
+ 0x0C},
+ /* Index 0xE8~0xEB */
+ {0x10, 0x0B, 0x0B}, {0x10, 0x0C, 0x0B}, {0x10, 0x0D, 0x0B}, {0x10,
+ 0x0F,
+ 0x0B},
+ /* Index 0xEC~0xEF */
+ {0x10, 0x10, 0x0B}, {0x0F, 0x10, 0x0B}, {0x0D, 0x10, 0x0B}, {0x0C,
+ 0x10,
+ 0x0B},
+ /* Index 0xF0~0xF3 */
+ {0x0B, 0x10, 0x0B}, {0x0B, 0x10, 0x0C}, {0x0B, 0x10, 0x0D}, {0x0B,
+ 0x10,
+ 0x0F},
+ /* Index 0xF4~0xF7 */
+ {0x0B, 0x10, 0x10}, {0x0B, 0x0F, 0x10}, {0x0B, 0x0D, 0x10}, {0x0B,
+ 0x0C,
+ 0x10},
+ /* Index 0xF8~0xFB */
+ {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00,
+ 0x00,
+ 0x00},
+ /* Index 0xFC~0xFF */
+ {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00,
+ 0x00,
+ 0x00}
+};
+
+static void set_crt_output_path(int set_iga);
+static void dvi_patch_skew_dvp0(void);
+static void dvi_patch_skew_dvp1(void);
+static void dvi_patch_skew_dvp_low(void);
+static void set_dvi_output_path(int set_iga, int output_interface);
+static void set_lcd_output_path(int set_iga, int output_interface);
+static int search_mode_setting(int ModeInfoIndex);
+static void load_fix_bit_crtc_reg(void);
+static void init_gfx_chip_info(void);
+static void init_tmds_chip_info(void);
+static void init_lvds_chip_info(void);
+static void device_screen_off(void);
+static void device_screen_on(void);
+static void set_display_channel(void);
+static void device_off(void);
+static void device_on(void);
+static void enable_second_display_channel(void);
+static void disable_second_display_channel(void);
+static int get_fb_size_from_pci(void);
+
+void viafb_write_reg(u8 index, u16 io_port, u8 data)
+{
+ outb(index, io_port);
+ outb(data, io_port + 1);
+ /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, data); */
+}
+u8 viafb_read_reg(int io_port, u8 index)
+{
+ outb(index, io_port);
+ return inb(io_port + 1);
+}
+
+void viafb_lock_crt(void)
+{
+ viafb_write_reg_mask(CR11, VIACR, BIT7, BIT7);
+}
+
+void viafb_unlock_crt(void)
+{
+ viafb_write_reg_mask(CR11, VIACR, 0, BIT7);
+ viafb_write_reg_mask(CR47, VIACR, 0, BIT0);
+}
+
+void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask)
+{
+ u8 tmp;
+
+ outb(index, io_port);
+ tmp = inb(io_port + 1);
+ outb((data & mask) | (tmp & (~mask)), io_port + 1);
+ /*DEBUG_MSG(KERN_INFO "\nIndex=%2d Value=%2d", index, tmp); */
+}
+
+void write_dac_reg(u8 index, u8 r, u8 g, u8 b)
+{
+ outb(index, LUT_INDEX_WRITE);
+ outb(r, LUT_DATA);
+ outb(g, LUT_DATA);
+ outb(b, LUT_DATA);
+}
+
+/*Set IGA path for each device*/
+void viafb_set_iga_path(void)
+{
+
+ if (viafb_SAMM_ON == 1) {
+ if (viafb_CRT_ON) {
+ if (viafb_primary_dev == CRT_Device)
+ viaparinfo->crt_setting_info->iga_path = IGA1;
+ else
+ viaparinfo->crt_setting_info->iga_path = IGA2;
+ }
+
+ if (viafb_DVI_ON) {
+ if (viafb_primary_dev == DVI_Device)
+ viaparinfo->tmds_setting_info->iga_path = IGA1;
+ else
+ viaparinfo->tmds_setting_info->iga_path = IGA2;
+ }
+
+ if (viafb_LCD_ON) {
+ if (viafb_primary_dev == LCD_Device) {
+ if (viafb_dual_fb &&
+ (viaparinfo->chip_info->gfx_chip_name ==
+ UNICHROME_CLE266)) {
+ viaparinfo->
+ lvds_setting_info->iga_path = IGA2;
+ viaparinfo->
+ crt_setting_info->iga_path = IGA1;
+ viaparinfo->
+ tmds_setting_info->iga_path = IGA1;
+ } else
+ viaparinfo->
+ lvds_setting_info->iga_path = IGA1;
+ } else {
+ viaparinfo->lvds_setting_info->iga_path = IGA2;
+ }
+ }
+ if (viafb_LCD2_ON) {
+ if (LCD2_Device == viafb_primary_dev)
+ viaparinfo->lvds_setting_info2->iga_path = IGA1;
+ else
+ viaparinfo->lvds_setting_info2->iga_path = IGA2;
+ }
+ } else {
+ viafb_SAMM_ON = 0;
+
+ if (viafb_CRT_ON && viafb_LCD_ON) {
+ viaparinfo->crt_setting_info->iga_path = IGA1;
+ viaparinfo->lvds_setting_info->iga_path = IGA2;
+ } else if (viafb_CRT_ON && viafb_DVI_ON) {
+ viaparinfo->crt_setting_info->iga_path = IGA1;
+ viaparinfo->tmds_setting_info->iga_path = IGA2;
+ } else if (viafb_LCD_ON && viafb_DVI_ON) {
+ viaparinfo->tmds_setting_info->iga_path = IGA1;
+ viaparinfo->lvds_setting_info->iga_path = IGA2;
+ } else if (viafb_LCD_ON && viafb_LCD2_ON) {
+ viaparinfo->lvds_setting_info->iga_path = IGA2;
+ viaparinfo->lvds_setting_info2->iga_path = IGA2;
+ } else if (viafb_CRT_ON) {
+ viaparinfo->crt_setting_info->iga_path = IGA1;
+ } else if (viafb_LCD_ON) {
+ viaparinfo->lvds_setting_info->iga_path = IGA2;
+ } else if (viafb_DVI_ON) {
+ viaparinfo->tmds_setting_info->iga_path = IGA1;
+ }
+ }
+}
+
+void viafb_set_start_addr(void)
+{
+ unsigned long offset = 0, tmp = 0, size = 0;
+ unsigned long length;
+
+ DEBUG_MSG(KERN_INFO "viafb_set_start_addr!\n");
+ viafb_unlock_crt();
+ /* update starting address of IGA1 */
+ viafb_write_reg(CR0C, VIACR, 0x00); /*initial starting address */
+ viafb_write_reg(CR0D, VIACR, 0x00);
+ viafb_write_reg(CR34, VIACR, 0x00);
+ viafb_write_reg_mask(CR48, VIACR, 0x00, 0x1F);
+
+ if (viafb_dual_fb) {
+ viaparinfo->iga_path = IGA1;
+ viaparinfo1->iga_path = IGA2;
+ }
+
+ if (viafb_SAMM_ON == 1) {
+ if (!viafb_dual_fb) {
+ if (viafb_second_size)
+ size = viafb_second_size * 1024 * 1024;
+ else
+ size = 8 * 1024 * 1024;
+ } else {
+
+ size = viaparinfo1->memsize;
+ }
+ offset = viafb_second_offset;
+ DEBUG_MSG(KERN_INFO
+ "viafb_second_size=%lx, second start_adddress=%lx\n",
+ size, offset);
+ }
+ if (viafb_SAMM_ON == 1) {
+ offset = offset >> 3;
+
+ tmp = viafb_read_reg(VIACR, 0x62) & 0x01;
+ tmp |= (offset & 0x7F) << 1;
+ viafb_write_reg(CR62, VIACR, tmp);
+ viafb_write_reg(CR63, VIACR, ((offset & 0x7F80) >> 7));
+ viafb_write_reg(CR64, VIACR, ((offset & 0x7F8000) >> 15));
+ viafb_write_reg(CRA3, VIACR, ((offset & 0x3800000) >> 23));
+ } else {
+ /* update starting address */
+ viafb_write_reg(CR62, VIACR, 0x00);
+ viafb_write_reg(CR63, VIACR, 0x00);
+ viafb_write_reg(CR64, VIACR, 0x00);
+ viafb_write_reg(CRA3, VIACR, 0x00);
+ }
+
+ if (viafb_SAMM_ON == 1) {
+ if (viafb_accel) {
+ if (!viafb_dual_fb)
+ length = size - viaparinfo->fbmem_used;
+ else
+ length = size - viaparinfo1->fbmem_used;
+ } else
+ length = size;
+ offset = (unsigned long)(void *)viafb_FB_MM +
+ viafb_second_offset;
+ memset((void *)offset, 0, length);
+ }
+
+ viafb_lock_crt();
+}
+
+void viafb_set_output_path(int device, int set_iga, int output_interface)
+{
+ switch (device) {
+ case DEVICE_CRT:
+ set_crt_output_path(set_iga);
+ break;
+ case DEVICE_DVI:
+ set_dvi_output_path(set_iga, output_interface);
+ break;
+ case DEVICE_LCD:
+ set_lcd_output_path(set_iga, output_interface);
+ break;
+ }
+}
+
+static void set_crt_output_path(int set_iga)
+{
+ viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+
+ switch (set_iga) {
+ case IGA1:
+ viafb_write_reg_mask(SR16, VIASR, 0x00, BIT6);
+ break;
+ case IGA2:
+ case IGA1_IGA2:
+ viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
+ viafb_write_reg_mask(SR16, VIASR, 0x40, BIT6);
+ if (set_iga == IGA1_IGA2)
+ viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
+ break;
+ }
+}
+
+static void dvi_patch_skew_dvp0(void)
+{
+ /* Reset data driving first: */
+ viafb_write_reg_mask(SR1B, VIASR, 0, BIT1);
+ viafb_write_reg_mask(SR2A, VIASR, 0, BIT4);
+
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_P4M890:
+ {
+ if ((viaparinfo->tmds_setting_info->h_active == 1600) &&
+ (viaparinfo->tmds_setting_info->v_active ==
+ 1200))
+ viafb_write_reg_mask(CR96, VIACR, 0x03,
+ BIT0 + BIT1 + BIT2);
+ else
+ viafb_write_reg_mask(CR96, VIACR, 0x07,
+ BIT0 + BIT1 + BIT2);
+ break;
+ }
+
+ case UNICHROME_P4M900:
+ {
+ viafb_write_reg_mask(CR96, VIACR, 0x07,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ viafb_write_reg_mask(SR1B, VIASR, 0x02, BIT1);
+ viafb_write_reg_mask(SR2A, VIASR, 0x10, BIT4);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+static void dvi_patch_skew_dvp1(void)
+{
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CX700:
+ {
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+static void dvi_patch_skew_dvp_low(void)
+{
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x03, BIT0 + BIT1);
+ break;
+ }
+
+ case UNICHROME_P4M900:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x08,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ break;
+ }
+
+ case UNICHROME_P4M890:
+ {
+ viafb_write_reg_mask(CR99, VIACR, 0x0F,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+}
+
+static void set_dvi_output_path(int set_iga, int output_interface)
+{
+ switch (output_interface) {
+ case INTERFACE_DVP0:
+ viafb_write_reg_mask(CR6B, VIACR, 0x01, BIT0);
+
+ if (set_iga == IGA1) {
+ viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+ viafb_write_reg_mask(CR6C, VIACR, 0x21, BIT0 +
+ BIT5 + BIT7);
+ } else {
+ viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR6C, VIACR, 0xA1, BIT0 +
+ BIT5 + BIT7);
+ }
+
+ viafb_write_reg_mask(SR1E, VIASR, 0xC0, BIT7 + BIT6);
+
+ dvi_patch_skew_dvp0();
+ break;
+
+ case INTERFACE_DVP1:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR93, VIACR, 0x21,
+ BIT0 + BIT5 + BIT7);
+ else
+ viafb_write_reg_mask(CR93, VIACR, 0xA1,
+ BIT0 + BIT5 + BIT7);
+ } else {
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+ else
+ viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+ }
+
+ viafb_write_reg_mask(SR1E, VIASR, 0x30, BIT4 + BIT5);
+ dvi_patch_skew_dvp1();
+ break;
+ case INTERFACE_DFP_HIGH:
+ if (viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266) {
+ if (set_iga == IGA1) {
+ viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+ viafb_write_reg_mask(CR97, VIACR, 0x03,
+ BIT0 + BIT1 + BIT4);
+ } else {
+ viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR97, VIACR, 0x13,
+ BIT0 + BIT1 + BIT4);
+ }
+ }
+ viafb_write_reg_mask(SR2A, VIASR, 0x0C, BIT2 + BIT3);
+ break;
+
+ case INTERFACE_DFP_LOW:
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ break;
+
+ if (set_iga == IGA1) {
+ viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+ viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+ } else {
+ viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+ }
+
+ viafb_write_reg_mask(SR2A, VIASR, 0x03, BIT0 + BIT1);
+ dvi_patch_skew_dvp_low();
+ break;
+
+ case INTERFACE_TMDS:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+ else
+ viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ break;
+ }
+
+ if (set_iga == IGA2) {
+ enable_second_display_channel();
+ /* Disable LCD Scaling */
+ viafb_write_reg_mask(CR79, VIACR, 0x00, BIT0);
+ }
+}
+
+static void set_lcd_output_path(int set_iga, int output_interface)
+{
+ DEBUG_MSG(KERN_INFO
+ "set_lcd_output_path, iga:%d,out_interface:%d\n",
+ set_iga, output_interface);
+ switch (set_iga) {
+ case IGA1:
+ viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+ disable_second_display_channel();
+ break;
+
+ case IGA2:
+ viafb_write_reg_mask(CR6B, VIACR, 0x00, BIT3);
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+ enable_second_display_channel();
+ break;
+
+ case IGA1_IGA2:
+ viafb_write_reg_mask(CR6B, VIACR, 0x08, BIT3);
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+
+ disable_second_display_channel();
+ break;
+ }
+
+ switch (output_interface) {
+ case INTERFACE_DVP0:
+ if (set_iga == IGA1) {
+ viafb_write_reg_mask(CR96, VIACR, 0x00, BIT4);
+ } else {
+ viafb_write_reg(CR91, VIACR, 0x00);
+ viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+ }
+ break;
+
+ case INTERFACE_DVP1:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR9B, VIACR, 0x00, BIT4);
+ else {
+ viafb_write_reg(CR91, VIACR, 0x00);
+ viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+ }
+ break;
+
+ case INTERFACE_DFP_HIGH:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+ else {
+ viafb_write_reg(CR91, VIACR, 0x00);
+ viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR96, VIACR, 0x10, BIT4);
+ }
+ break;
+
+ case INTERFACE_DFP_LOW:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+ else {
+ viafb_write_reg(CR91, VIACR, 0x00);
+ viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR9B, VIACR, 0x10, BIT4);
+ }
+
+ break;
+
+ case INTERFACE_DFP:
+ if ((UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name)
+ || (UNICHROME_P4M890 ==
+ viaparinfo->chip_info->gfx_chip_name))
+ viafb_write_reg_mask(CR97, VIACR, 0x84,
+ BIT7 + BIT2 + BIT1 + BIT0);
+ if (set_iga == IGA1) {
+ viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+ viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+ } else {
+ viafb_write_reg(CR91, VIACR, 0x00);
+ viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+ viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+ }
+ break;
+
+ case INTERFACE_LVDS0:
+ case INTERFACE_LVDS0LVDS1:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR99, VIACR, 0x00, BIT4);
+ else
+ viafb_write_reg_mask(CR99, VIACR, 0x10, BIT4);
+
+ break;
+
+ case INTERFACE_LVDS1:
+ if (set_iga == IGA1)
+ viafb_write_reg_mask(CR97, VIACR, 0x00, BIT4);
+ else
+ viafb_write_reg_mask(CR97, VIACR, 0x10, BIT4);
+ break;
+ }
+}
+
+/* Search Mode Index */
+static int search_mode_setting(int ModeInfoIndex)
+{
+ int i = 0;
+
+ while ((i < NUM_TOTAL_MODETABLE) &&
+ (ModeInfoIndex != CLE266Modes[i].ModeIndex))
+ i++;
+ if (i >= NUM_TOTAL_MODETABLE)
+ i = 0;
+ return i;
+
+}
+
+struct VideoModeTable *viafb_get_modetbl_pointer(int Index)
+{
+ struct VideoModeTable *TmpTbl = NULL;
+ TmpTbl = &CLE266Modes[search_mode_setting(Index)];
+ return TmpTbl;
+}
+
+struct VideoModeTable *viafb_get_cea_mode_tbl_pointer(int Index)
+{
+ struct VideoModeTable *TmpTbl = NULL;
+ int i = 0;
+ while ((i < NUM_TOTAL_CEA_MODES) &&
+ (Index != CEA_HDMI_Modes[i].ModeIndex))
+ i++;
+ if ((i < NUM_TOTAL_CEA_MODES))
+ TmpTbl = &CEA_HDMI_Modes[i];
+ else {
+ /*Still use general timing if don't find CEA timing */
+ i = 0;
+ while ((i < NUM_TOTAL_MODETABLE) &&
+ (Index != CLE266Modes[i].ModeIndex))
+ i++;
+ if (i >= NUM_TOTAL_MODETABLE)
+ i = 0;
+ TmpTbl = &CLE266Modes[i];
+ }
+ return TmpTbl;
+}
+
+static void load_fix_bit_crtc_reg(void)
+{
+ /* always set to 1 */
+ viafb_write_reg_mask(CR03, VIACR, 0x80, BIT7);
+ /* line compare should set all bits = 1 (extend modes) */
+ viafb_write_reg(CR18, VIACR, 0xff);
+ /* line compare should set all bits = 1 (extend modes) */
+ viafb_write_reg_mask(CR07, VIACR, 0x10, BIT4);
+ /* line compare should set all bits = 1 (extend modes) */
+ viafb_write_reg_mask(CR09, VIACR, 0x40, BIT6);
+ /* line compare should set all bits = 1 (extend modes) */
+ viafb_write_reg_mask(CR35, VIACR, 0x10, BIT4);
+ /* line compare should set all bits = 1 (extend modes) */
+ viafb_write_reg_mask(CR33, VIACR, 0x06, BIT0 + BIT1 + BIT2);
+ /*viafb_write_reg_mask(CR32, VIACR, 0x01, BIT0); */
+ /* extend mode always set to e3h */
+ viafb_write_reg(CR17, VIACR, 0xe3);
+ /* extend mode always set to 0h */
+ viafb_write_reg(CR08, VIACR, 0x00);
+ /* extend mode always set to 0h */
+ viafb_write_reg(CR14, VIACR, 0x00);
+
+ /* If K8M800, enable Prefetch Mode. */
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
+ || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890))
+ viafb_write_reg_mask(CR33, VIACR, 0x08, BIT3);
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ && (viaparinfo->chip_info->gfx_chip_revision == CLE266_REVISION_AX))
+ viafb_write_reg_mask(SR1A, VIASR, 0x02, BIT1);
+
+}
+
+void viafb_load_reg(int timing_value, int viafb_load_reg_num,
+ struct io_register *reg,
+ int io_type)
+{
+ int reg_mask;
+ int bit_num = 0;
+ int data;
+ int i, j;
+ int shift_next_reg;
+ int start_index, end_index, cr_index;
+ u16 get_bit;
+
+ for (i = 0; i < viafb_load_reg_num; i++) {
+ reg_mask = 0;
+ data = 0;
+ start_index = reg[i].start_bit;
+ end_index = reg[i].end_bit;
+ cr_index = reg[i].io_addr;
+
+ shift_next_reg = bit_num;
+ for (j = start_index; j <= end_index; j++) {
+ /*if (bit_num==8) timing_value = timing_value >>8; */
+ reg_mask = reg_mask | (BIT0 << j);
+ get_bit = (timing_value & (BIT0 << bit_num));
+ data =
+ data | ((get_bit >> shift_next_reg) << start_index);
+ bit_num++;
+ }
+ if (io_type == VIACR)
+ viafb_write_reg_mask(cr_index, VIACR, data, reg_mask);
+ else
+ viafb_write_reg_mask(cr_index, VIASR, data, reg_mask);
+ }
+
+}
+
+/* Write Registers */
+void viafb_write_regx(struct io_reg RegTable[], int ItemNum)
+{
+ int i;
+ unsigned char RegTemp;
+
+ /*DEBUG_MSG(KERN_INFO "Table Size : %x!!\n",ItemNum ); */
+
+ for (i = 0; i < ItemNum; i++) {
+ outb(RegTable[i].index, RegTable[i].port);
+ RegTemp = inb(RegTable[i].port + 1);
+ RegTemp = (RegTemp & (~RegTable[i].mask)) | RegTable[i].value;
+ outb(RegTemp, RegTable[i].port + 1);
+ }
+}
+
+void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga)
+{
+ int reg_value;
+ int viafb_load_reg_num;
+ struct io_register *reg;
+
+ switch (set_iga) {
+ case IGA1_IGA2:
+ case IGA1:
+ reg_value = IGA1_OFFSET_FORMULA(h_addr, bpp_byte);
+ viafb_load_reg_num = offset_reg.iga1_offset_reg.reg_num;
+ reg = offset_reg.iga1_offset_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+ if (set_iga == IGA1)
+ break;
+ case IGA2:
+ reg_value = IGA2_OFFSET_FORMULA(h_addr, bpp_byte);
+ viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num;
+ reg = offset_reg.iga2_offset_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+ break;
+ }
+}
+
+void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga)
+{
+ int reg_value;
+ int viafb_load_reg_num;
+ struct io_register *reg = NULL;
+
+ switch (set_iga) {
+ case IGA1_IGA2:
+ case IGA1:
+ reg_value = IGA1_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
+ viafb_load_reg_num = fetch_count_reg.
+ iga1_fetch_count_reg.reg_num;
+ reg = fetch_count_reg.iga1_fetch_count_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+ if (set_iga == IGA1)
+ break;
+ case IGA2:
+ reg_value = IGA2_FETCH_COUNT_FORMULA(h_addr, bpp_byte);
+ viafb_load_reg_num = fetch_count_reg.
+ iga2_fetch_count_reg.reg_num;
+ reg = fetch_count_reg.iga2_fetch_count_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+ break;
+ }
+
+}
+
+void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
+{
+ int reg_value;
+ int viafb_load_reg_num;
+ struct io_register *reg = NULL;
+ int iga1_fifo_max_depth = 0, iga1_fifo_threshold =
+ 0, iga1_fifo_high_threshold = 0, iga1_display_queue_expire_num = 0;
+ int iga2_fifo_max_depth = 0, iga2_fifo_threshold =
+ 0, iga2_fifo_high_threshold = 0, iga2_display_queue_expire_num = 0;
+
+ if (set_iga == IGA1) {
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+ iga1_fifo_max_depth = K800_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = K800_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ K800_IGA1_FIFO_HIGH_THRESHOLD;
+ /* If resolution > 1280x1024, expire length = 64, else
+ expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga1_display_queue_expire_num = 16;
+ else
+ iga1_display_queue_expire_num =
+ K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) {
+ iga1_fifo_max_depth = P880_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = P880_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ P880_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+
+ /* If resolution > 1280x1024, expire length = 64, else
+ expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga1_display_queue_expire_num = 16;
+ else
+ iga1_display_queue_expire_num =
+ P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) {
+ iga1_fifo_max_depth = CN700_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = CN700_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ CN700_IGA1_FIFO_HIGH_THRESHOLD;
+
+ /* If resolution > 1280x1024, expire length = 64,
+ else expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga1_display_queue_expire_num = 16;
+ else
+ iga1_display_queue_expire_num =
+ CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+ iga1_fifo_max_depth = CX700_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = CX700_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ CX700_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) {
+ iga1_fifo_max_depth = K8M890_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = K8M890_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ K8M890_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) {
+ iga1_fifo_max_depth = P4M890_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = P4M890_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ P4M890_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) {
+ iga1_fifo_max_depth = P4M900_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = P4M900_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ P4M900_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) {
+ iga1_fifo_max_depth = VX800_IGA1_FIFO_MAX_DEPTH;
+ iga1_fifo_threshold = VX800_IGA1_FIFO_THRESHOLD;
+ iga1_fifo_high_threshold =
+ VX800_IGA1_FIFO_HIGH_THRESHOLD;
+ iga1_display_queue_expire_num =
+ VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ /* Set Display FIFO Depath Select */
+ reg_value = IGA1_FIFO_DEPTH_SELECT_FORMULA(iga1_fifo_max_depth);
+ viafb_load_reg_num =
+ display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg_num;
+ reg = display_fifo_depth_reg.iga1_fifo_depth_select_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+ /* Set Display FIFO Threshold Select */
+ reg_value = IGA1_FIFO_THRESHOLD_FORMULA(iga1_fifo_threshold);
+ viafb_load_reg_num =
+ fifo_threshold_select_reg.
+ iga1_fifo_threshold_select_reg.reg_num;
+ reg =
+ fifo_threshold_select_reg.
+ iga1_fifo_threshold_select_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+ /* Set FIFO High Threshold Select */
+ reg_value =
+ IGA1_FIFO_HIGH_THRESHOLD_FORMULA(iga1_fifo_high_threshold);
+ viafb_load_reg_num =
+ fifo_high_threshold_select_reg.
+ iga1_fifo_high_threshold_select_reg.reg_num;
+ reg =
+ fifo_high_threshold_select_reg.
+ iga1_fifo_high_threshold_select_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+ /* Set Display Queue Expire Num */
+ reg_value =
+ IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA
+ (iga1_display_queue_expire_num);
+ viafb_load_reg_num =
+ display_queue_expire_num_reg.
+ iga1_display_queue_expire_num_reg.reg_num;
+ reg =
+ display_queue_expire_num_reg.
+ iga1_display_queue_expire_num_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIASR);
+
+ } else {
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+ iga2_fifo_max_depth = K800_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = K800_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ K800_IGA2_FIFO_HIGH_THRESHOLD;
+
+ /* If resolution > 1280x1024, expire length = 64,
+ else expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga2_display_queue_expire_num = 16;
+ else
+ iga2_display_queue_expire_num =
+ K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_PM800) {
+ iga2_fifo_max_depth = P880_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = P880_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ P880_IGA2_FIFO_HIGH_THRESHOLD;
+
+ /* If resolution > 1280x1024, expire length = 64,
+ else expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga2_display_queue_expire_num = 16;
+ else
+ iga2_display_queue_expire_num =
+ P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CN700) {
+ iga2_fifo_max_depth = CN700_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = CN700_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ CN700_IGA2_FIFO_HIGH_THRESHOLD;
+
+ /* If resolution > 1280x1024, expire length = 64,
+ else expire length = 128 */
+ if ((hor_active > 1280) && (ver_active > 1024))
+ iga2_display_queue_expire_num = 16;
+ else
+ iga2_display_queue_expire_num =
+ CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+ iga2_fifo_max_depth = CX700_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = CX700_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ CX700_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K8M890) {
+ iga2_fifo_max_depth = K8M890_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = K8M890_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ K8M890_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M890) {
+ iga2_fifo_max_depth = P4M890_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = P4M890_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ P4M890_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_P4M900) {
+ iga2_fifo_max_depth = P4M900_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = P4M900_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ P4M900_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_VX800) {
+ iga2_fifo_max_depth = VX800_IGA2_FIFO_MAX_DEPTH;
+ iga2_fifo_threshold = VX800_IGA2_FIFO_THRESHOLD;
+ iga2_fifo_high_threshold =
+ VX800_IGA2_FIFO_HIGH_THRESHOLD;
+ iga2_display_queue_expire_num =
+ VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM;
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800) {
+ /* Set Display FIFO Depath Select */
+ reg_value =
+ IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth)
+ - 1;
+ /* Patch LCD in IGA2 case */
+ viafb_load_reg_num =
+ display_fifo_depth_reg.
+ iga2_fifo_depth_select_reg.reg_num;
+ reg =
+ display_fifo_depth_reg.
+ iga2_fifo_depth_select_reg.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ } else {
+
+ /* Set Display FIFO Depath Select */
+ reg_value =
+ IGA2_FIFO_DEPTH_SELECT_FORMULA(iga2_fifo_max_depth);
+ viafb_load_reg_num =
+ display_fifo_depth_reg.
+ iga2_fifo_depth_select_reg.reg_num;
+ reg =
+ display_fifo_depth_reg.
+ iga2_fifo_depth_select_reg.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ }
+
+ /* Set Display FIFO Threshold Select */
+ reg_value = IGA2_FIFO_THRESHOLD_FORMULA(iga2_fifo_threshold);
+ viafb_load_reg_num =
+ fifo_threshold_select_reg.
+ iga2_fifo_threshold_select_reg.reg_num;
+ reg =
+ fifo_threshold_select_reg.
+ iga2_fifo_threshold_select_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+ /* Set FIFO High Threshold Select */
+ reg_value =
+ IGA2_FIFO_HIGH_THRESHOLD_FORMULA(iga2_fifo_high_threshold);
+ viafb_load_reg_num =
+ fifo_high_threshold_select_reg.
+ iga2_fifo_high_threshold_select_reg.reg_num;
+ reg =
+ fifo_high_threshold_select_reg.
+ iga2_fifo_high_threshold_select_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+ /* Set Display Queue Expire Num */
+ reg_value =
+ IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA
+ (iga2_display_queue_expire_num);
+ viafb_load_reg_num =
+ display_queue_expire_num_reg.
+ iga2_display_queue_expire_num_reg.reg_num;
+ reg =
+ display_queue_expire_num_reg.
+ iga2_display_queue_expire_num_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+
+ }
+
+}
+
+u32 viafb_get_clk_value(int clk)
+{
+ int i;
+
+ for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
+ if (clk == pll_value[i].clk) {
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ return pll_value[i].cle266_pll;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ return pll_value[i].k800_pll;
+
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ case UNICHROME_VX800:
+ return pll_value[i].cx700_pll;
+ }
+ }
+ }
+
+ DEBUG_MSG(KERN_INFO "Can't find match PLL value\n\n");
+ return 0;
+}
+
+/* Set VCLK*/
+void viafb_set_vclock(u32 CLK, int set_iga)
+{
+ unsigned char RegTemp;
+
+ /* H.W. Reset : ON */
+ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+ if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+ /* Change D,N FOR VCLK */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ viafb_write_reg(SR46, VIASR, CLK / 0x100);
+ viafb_write_reg(SR47, VIASR, CLK % 0x100);
+ break;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ case UNICHROME_VX800:
+ viafb_write_reg(SR44, VIASR, CLK / 0x10000);
+ DEBUG_MSG(KERN_INFO "\nSR44=%x", CLK / 0x10000);
+ viafb_write_reg(SR45, VIASR, (CLK & 0xFFFF) / 0x100);
+ DEBUG_MSG(KERN_INFO "\nSR45=%x",
+ (CLK & 0xFFFF) / 0x100);
+ viafb_write_reg(SR46, VIASR, CLK % 0x100);
+ DEBUG_MSG(KERN_INFO "\nSR46=%x", CLK % 0x100);
+ break;
+ }
+ }
+
+ if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+ /* Change D,N FOR LCK */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ viafb_write_reg(SR44, VIASR, CLK / 0x100);
+ viafb_write_reg(SR45, VIASR, CLK % 0x100);
+ break;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ case UNICHROME_VX800:
+ viafb_write_reg(SR4A, VIASR, CLK / 0x10000);
+ viafb_write_reg(SR4B, VIASR, (CLK & 0xFFFF) / 0x100);
+ viafb_write_reg(SR4C, VIASR, CLK % 0x100);
+ break;
+ }
+ }
+
+ /* H.W. Reset : OFF */
+ viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+ /* Reset PLL */
+ if ((set_iga == IGA1) || (set_iga == IGA1_IGA2)) {
+ viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+ viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+ }
+
+ if ((set_iga == IGA2) || (set_iga == IGA1_IGA2)) {
+ viafb_write_reg_mask(SR40, VIASR, 0x01, BIT0);
+ viafb_write_reg_mask(SR40, VIASR, 0x00, BIT0);
+ }
+
+ /* Fire! */
+ RegTemp = inb(VIARMisc);
+ outb(RegTemp | (BIT2 + BIT3), VIAWMisc);
+}
+
+void viafb_load_crtc_timing(struct display_timing device_timing,
+ int set_iga)
+{
+ int i;
+ int viafb_load_reg_num = 0;
+ int reg_value = 0;
+ struct io_register *reg = NULL;
+
+ viafb_unlock_crt();
+
+ for (i = 0; i < 12; i++) {
+ if (set_iga == IGA1) {
+ switch (i) {
+ case H_TOTAL_INDEX:
+ reg_value =
+ IGA1_HOR_TOTAL_FORMULA(device_timing.
+ hor_total);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_total.reg_num;
+ reg = iga1_crtc_reg.hor_total.reg;
+ break;
+ case H_ADDR_INDEX:
+ reg_value =
+ IGA1_HOR_ADDR_FORMULA(device_timing.
+ hor_addr);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_addr.reg_num;
+ reg = iga1_crtc_reg.hor_addr.reg;
+ break;
+ case H_BLANK_START_INDEX:
+ reg_value =
+ IGA1_HOR_BLANK_START_FORMULA
+ (device_timing.hor_blank_start);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_blank_start.reg_num;
+ reg = iga1_crtc_reg.hor_blank_start.reg;
+ break;
+ case H_BLANK_END_INDEX:
+ reg_value =
+ IGA1_HOR_BLANK_END_FORMULA
+ (device_timing.hor_blank_start,
+ device_timing.hor_blank_end);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_blank_end.reg_num;
+ reg = iga1_crtc_reg.hor_blank_end.reg;
+ break;
+ case H_SYNC_START_INDEX:
+ reg_value =
+ IGA1_HOR_SYNC_START_FORMULA
+ (device_timing.hor_sync_start);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_sync_start.reg_num;
+ reg = iga1_crtc_reg.hor_sync_start.reg;
+ break;
+ case H_SYNC_END_INDEX:
+ reg_value =
+ IGA1_HOR_SYNC_END_FORMULA
+ (device_timing.hor_sync_start,
+ device_timing.hor_sync_end);
+ viafb_load_reg_num =
+ iga1_crtc_reg.hor_sync_end.reg_num;
+ reg = iga1_crtc_reg.hor_sync_end.reg;
+ break;
+ case V_TOTAL_INDEX:
+ reg_value =
+ IGA1_VER_TOTAL_FORMULA(device_timing.
+ ver_total);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_total.reg_num;
+ reg = iga1_crtc_reg.ver_total.reg;
+ break;
+ case V_ADDR_INDEX:
+ reg_value =
+ IGA1_VER_ADDR_FORMULA(device_timing.
+ ver_addr);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_addr.reg_num;
+ reg = iga1_crtc_reg.ver_addr.reg;
+ break;
+ case V_BLANK_START_INDEX:
+ reg_value =
+ IGA1_VER_BLANK_START_FORMULA
+ (device_timing.ver_blank_start);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_blank_start.reg_num;
+ reg = iga1_crtc_reg.ver_blank_start.reg;
+ break;
+ case V_BLANK_END_INDEX:
+ reg_value =
+ IGA1_VER_BLANK_END_FORMULA
+ (device_timing.ver_blank_start,
+ device_timing.ver_blank_end);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_blank_end.reg_num;
+ reg = iga1_crtc_reg.ver_blank_end.reg;
+ break;
+ case V_SYNC_START_INDEX:
+ reg_value =
+ IGA1_VER_SYNC_START_FORMULA
+ (device_timing.ver_sync_start);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_sync_start.reg_num;
+ reg = iga1_crtc_reg.ver_sync_start.reg;
+ break;
+ case V_SYNC_END_INDEX:
+ reg_value =
+ IGA1_VER_SYNC_END_FORMULA
+ (device_timing.ver_sync_start,
+ device_timing.ver_sync_end);
+ viafb_load_reg_num =
+ iga1_crtc_reg.ver_sync_end.reg_num;
+ reg = iga1_crtc_reg.ver_sync_end.reg;
+ break;
+
+ }
+ }
+
+ if (set_iga == IGA2) {
+ switch (i) {
+ case H_TOTAL_INDEX:
+ reg_value =
+ IGA2_HOR_TOTAL_FORMULA(device_timing.
+ hor_total);
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_total.reg_num;
+ reg = iga2_crtc_reg.hor_total.reg;
+ break;
+ case H_ADDR_INDEX:
+ reg_value =
+ IGA2_HOR_ADDR_FORMULA(device_timing.
+ hor_addr);
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_addr.reg_num;
+ reg = iga2_crtc_reg.hor_addr.reg;
+ break;
+ case H_BLANK_START_INDEX:
+ reg_value =
+ IGA2_HOR_BLANK_START_FORMULA
+ (device_timing.hor_blank_start);
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_blank_start.reg_num;
+ reg = iga2_crtc_reg.hor_blank_start.reg;
+ break;
+ case H_BLANK_END_INDEX:
+ reg_value =
+ IGA2_HOR_BLANK_END_FORMULA
+ (device_timing.hor_blank_start,
+ device_timing.hor_blank_end);
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_blank_end.reg_num;
+ reg = iga2_crtc_reg.hor_blank_end.reg;
+ break;
+ case H_SYNC_START_INDEX:
+ reg_value =
+ IGA2_HOR_SYNC_START_FORMULA
+ (device_timing.hor_sync_start);
+ if (UNICHROME_CN700 <=
+ viaparinfo->chip_info->gfx_chip_name)
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_sync_start.
+ reg_num;
+ else
+ viafb_load_reg_num = 3;
+ reg = iga2_crtc_reg.hor_sync_start.reg;
+ break;
+ case H_SYNC_END_INDEX:
+ reg_value =
+ IGA2_HOR_SYNC_END_FORMULA
+ (device_timing.hor_sync_start,
+ device_timing.hor_sync_end);
+ viafb_load_reg_num =
+ iga2_crtc_reg.hor_sync_end.reg_num;
+ reg = iga2_crtc_reg.hor_sync_end.reg;
+ break;
+ case V_TOTAL_INDEX:
+ reg_value =
+ IGA2_VER_TOTAL_FORMULA(device_timing.
+ ver_total);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_total.reg_num;
+ reg = iga2_crtc_reg.ver_total.reg;
+ break;
+ case V_ADDR_INDEX:
+ reg_value =
+ IGA2_VER_ADDR_FORMULA(device_timing.
+ ver_addr);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_addr.reg_num;
+ reg = iga2_crtc_reg.ver_addr.reg;
+ break;
+ case V_BLANK_START_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_START_FORMULA
+ (device_timing.ver_blank_start);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_blank_start.reg_num;
+ reg = iga2_crtc_reg.ver_blank_start.reg;
+ break;
+ case V_BLANK_END_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_END_FORMULA
+ (device_timing.ver_blank_start,
+ device_timing.ver_blank_end);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_blank_end.reg_num;
+ reg = iga2_crtc_reg.ver_blank_end.reg;
+ break;
+ case V_SYNC_START_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_START_FORMULA
+ (device_timing.ver_sync_start);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_sync_start.reg_num;
+ reg = iga2_crtc_reg.ver_sync_start.reg;
+ break;
+ case V_SYNC_END_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_END_FORMULA
+ (device_timing.ver_sync_start,
+ device_timing.ver_sync_end);
+ viafb_load_reg_num =
+ iga2_crtc_reg.ver_sync_end.reg_num;
+ reg = iga2_crtc_reg.ver_sync_end.reg;
+ break;
+
+ }
+ }
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+ }
+
+ viafb_lock_crt();
+}
+
+void viafb_set_color_depth(int bpp_byte, int set_iga)
+{
+ if (set_iga == IGA1) {
+ switch (bpp_byte) {
+ case MODE_8BPP:
+ viafb_write_reg_mask(SR15, VIASR, 0x22, 0x7E);
+ break;
+ case MODE_16BPP:
+ viafb_write_reg_mask(SR15, VIASR, 0xB6, 0xFE);
+ break;
+ case MODE_32BPP:
+ viafb_write_reg_mask(SR15, VIASR, 0xAE, 0xFE);
+ break;
+ }
+ } else {
+ switch (bpp_byte) {
+ case MODE_8BPP:
+ viafb_write_reg_mask(CR67, VIACR, 0x00, BIT6 + BIT7);
+ break;
+ case MODE_16BPP:
+ viafb_write_reg_mask(CR67, VIACR, 0x40, BIT6 + BIT7);
+ break;
+ case MODE_32BPP:
+ viafb_write_reg_mask(CR67, VIACR, 0xC0, BIT6 + BIT7);
+ break;
+ }
+ }
+}
+
+void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
+ int mode_index, int bpp_byte, int set_iga)
+{
+ struct VideoModeTable *video_mode;
+ struct display_timing crt_reg;
+ int i;
+ int index = 0;
+ int h_addr, v_addr;
+ u32 pll_D_N;
+
+ video_mode = &CLE266Modes[search_mode_setting(mode_index)];
+
+ for (i = 0; i < video_mode->mode_array; i++) {
+ index = i;
+
+ if (crt_table[i].refresh_rate == viaparinfo->
+ crt_setting_info->refresh_rate)
+ break;
+ }
+
+ crt_reg = crt_table[index].crtc;
+
+ /* Mode 640x480 has border, but LCD/DFP didn't have border. */
+ /* So we would delete border. */
+ if ((viafb_LCD_ON | viafb_DVI_ON) && (mode_index == VIA_RES_640X480)
+ && (viaparinfo->crt_setting_info->refresh_rate == 60)) {
+ /* The border is 8 pixels. */
+ crt_reg.hor_blank_start = crt_reg.hor_blank_start - 8;
+
+ /* Blanking time should add left and right borders. */
+ crt_reg.hor_blank_end = crt_reg.hor_blank_end + 16;
+ }
+
+ h_addr = crt_reg.hor_addr;
+ v_addr = crt_reg.ver_addr;
+
+ /* update polarity for CRT timing */
+ if (crt_table[index].h_sync_polarity == NEGATIVE) {
+ if (crt_table[index].v_sync_polarity == NEGATIVE)
+ outb((inb(VIARMisc) & (~(BIT6 + BIT7))) |
+ (BIT6 + BIT7), VIAWMisc);
+ else
+ outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT6),
+ VIAWMisc);
+ } else {
+ if (crt_table[index].v_sync_polarity == NEGATIVE)
+ outb((inb(VIARMisc) & (~(BIT6 + BIT7))) | (BIT7),
+ VIAWMisc);
+ else
+ outb((inb(VIARMisc) & (~(BIT6 + BIT7))), VIAWMisc);
+ }
+
+ if (set_iga == IGA1) {
+ viafb_unlock_crt();
+ viafb_write_reg(CR09, VIACR, 0x00); /*initial CR09=0 */
+ viafb_write_reg_mask(CR11, VIACR, 0x00, BIT4 + BIT5 + BIT6);
+ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+ }
+
+ switch (set_iga) {
+ case IGA1:
+ viafb_load_crtc_timing(crt_reg, IGA1);
+ break;
+ case IGA2:
+ viafb_load_crtc_timing(crt_reg, IGA2);
+ break;
+ }
+
+ load_fix_bit_crtc_reg();
+ viafb_lock_crt();
+ viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+ viafb_load_offset_reg(h_addr, bpp_byte, set_iga);
+ viafb_load_fetch_count_reg(h_addr, bpp_byte, set_iga);
+
+ /* load FIFO */
+ if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+ && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
+ viafb_load_FIFO_reg(set_iga, h_addr, v_addr);
+
+ /* load SR Register About Memory and Color part */
+ viafb_set_color_depth(bpp_byte, set_iga);
+
+ pll_D_N = viafb_get_clk_value(crt_table[index].clk);
+ DEBUG_MSG(KERN_INFO "PLL=%x", pll_D_N);
+ viafb_set_vclock(pll_D_N, set_iga);
+
+}
+
+void viafb_init_chip_info(void)
+{
+ init_gfx_chip_info();
+ init_tmds_chip_info();
+ init_lvds_chip_info();
+
+ viaparinfo->crt_setting_info->iga_path = IGA1;
+ viaparinfo->crt_setting_info->refresh_rate = viafb_refresh;
+
+ /*Set IGA path for each device */
+ viafb_set_iga_path();
+
+ viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method;
+ viaparinfo->lvds_setting_info->get_lcd_size_method =
+ GET_LCD_SIZE_BY_USER_SETTING;
+ viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode;
+ viaparinfo->lvds_setting_info2->display_method =
+ viaparinfo->lvds_setting_info->display_method;
+ viaparinfo->lvds_setting_info2->lcd_mode =
+ viaparinfo->lvds_setting_info->lcd_mode;
+}
+
+void viafb_update_device_setting(int hres, int vres,
+ int bpp, int vmode_refresh, int flag)
+{
+ if (flag == 0) {
+ viaparinfo->crt_setting_info->h_active = hres;
+ viaparinfo->crt_setting_info->v_active = vres;
+ viaparinfo->crt_setting_info->bpp = bpp;
+ viaparinfo->crt_setting_info->refresh_rate =
+ vmode_refresh;
+
+ viaparinfo->tmds_setting_info->h_active = hres;
+ viaparinfo->tmds_setting_info->v_active = vres;
+ viaparinfo->tmds_setting_info->bpp = bpp;
+ viaparinfo->tmds_setting_info->refresh_rate =
+ vmode_refresh;
+
+ viaparinfo->lvds_setting_info->h_active = hres;
+ viaparinfo->lvds_setting_info->v_active = vres;
+ viaparinfo->lvds_setting_info->bpp = bpp;
+ viaparinfo->lvds_setting_info->refresh_rate =
+ vmode_refresh;
+ viaparinfo->lvds_setting_info2->h_active = hres;
+ viaparinfo->lvds_setting_info2->v_active = vres;
+ viaparinfo->lvds_setting_info2->bpp = bpp;
+ viaparinfo->lvds_setting_info2->refresh_rate =
+ vmode_refresh;
+ } else {
+
+ if (viaparinfo->tmds_setting_info->iga_path == IGA2) {
+ viaparinfo->tmds_setting_info->h_active = hres;
+ viaparinfo->tmds_setting_info->v_active = vres;
+ viaparinfo->tmds_setting_info->bpp = bpp;
+ viaparinfo->tmds_setting_info->refresh_rate =
+ vmode_refresh;
+ }
+
+ if (viaparinfo->lvds_setting_info->iga_path == IGA2) {
+ viaparinfo->lvds_setting_info->h_active = hres;
+ viaparinfo->lvds_setting_info->v_active = vres;
+ viaparinfo->lvds_setting_info->bpp = bpp;
+ viaparinfo->lvds_setting_info->refresh_rate =
+ vmode_refresh;
+ }
+ if (IGA2 == viaparinfo->lvds_setting_info2->iga_path) {
+ viaparinfo->lvds_setting_info2->h_active = hres;
+ viaparinfo->lvds_setting_info2->v_active = vres;
+ viaparinfo->lvds_setting_info2->bpp = bpp;
+ viaparinfo->lvds_setting_info2->refresh_rate =
+ vmode_refresh;
+ }
+ }
+}
+
+static void init_gfx_chip_info(void)
+{
+ struct pci_dev *pdev = NULL;
+ u32 i;
+ u8 tmp;
+
+ /* Indentify GFX Chip Name */
+ for (i = 0; pciidlist[i].vendor != 0; i++) {
+ pdev = pci_get_device(pciidlist[i].vendor,
+ pciidlist[i].device, 0);
+ if (pdev)
+ break;
+ }
+
+ if (!pciidlist[i].vendor)
+ return ;
+
+ viaparinfo->chip_info->gfx_chip_name = pciidlist[i].chip_index;
+
+ /* Check revision of CLE266 Chip */
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ /* CR4F only define in CLE266.CX chip */
+ tmp = viafb_read_reg(VIACR, CR4F);
+ viafb_write_reg(CR4F, VIACR, 0x55);
+ if (viafb_read_reg(VIACR, CR4F) != 0x55)
+ viaparinfo->chip_info->gfx_chip_revision =
+ CLE266_REVISION_AX;
+ else
+ viaparinfo->chip_info->gfx_chip_revision =
+ CLE266_REVISION_CX;
+ /* restore orignal CR4F value */
+ viafb_write_reg(CR4F, VIACR, tmp);
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+ tmp = viafb_read_reg(VIASR, SR43);
+ DEBUG_MSG(KERN_INFO "SR43:%X\n", tmp);
+ if (tmp & 0x02) {
+ viaparinfo->chip_info->gfx_chip_revision =
+ CX700_REVISION_700M2;
+ } else if (tmp & 0x40) {
+ viaparinfo->chip_info->gfx_chip_revision =
+ CX700_REVISION_700M;
+ } else {
+ viaparinfo->chip_info->gfx_chip_revision =
+ CX700_REVISION_700;
+ }
+ }
+
+ pci_dev_put(pdev);
+}
+
+static void init_tmds_chip_info(void)
+{
+ viafb_tmds_trasmitter_identify();
+
+ if (INTERFACE_NONE == viaparinfo->chip_info->tmds_chip_info.
+ output_interface) {
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CX700:
+ {
+ /* we should check support by hardware layout.*/
+ if ((viafb_display_hardware_layout ==
+ HW_LAYOUT_DVI_ONLY)
+ || (viafb_display_hardware_layout ==
+ HW_LAYOUT_LCD_DVI)) {
+ viaparinfo->chip_info->tmds_chip_info.
+ output_interface = INTERFACE_TMDS;
+ } else {
+ viaparinfo->chip_info->tmds_chip_info.
+ output_interface =
+ INTERFACE_NONE;
+ }
+ break;
+ }
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ case UNICHROME_P4M890:
+ /* TMDS on PCIE, we set DFPLOW as default. */
+ viaparinfo->chip_info->tmds_chip_info.output_interface =
+ INTERFACE_DFP_LOW;
+ break;
+ default:
+ {
+ /* set DVP1 default for DVI */
+ viaparinfo->chip_info->tmds_chip_info
+ .output_interface = INTERFACE_DVP1;
+ }
+ }
+ }
+
+ DEBUG_MSG(KERN_INFO "TMDS Chip = %d\n",
+ viaparinfo->chip_info->tmds_chip_info.tmds_chip_name);
+ viaparinfo->tmds_setting_info->get_dvi_size_method =
+ GET_DVI_SIZE_BY_VGA_BIOS;
+ viafb_init_dvi_size();
+}
+
+static void init_lvds_chip_info(void)
+{
+ if (viafb_lcd_panel_id > LCD_PANEL_ID_MAXIMUM)
+ viaparinfo->lvds_setting_info->get_lcd_size_method =
+ GET_LCD_SIZE_BY_VGA_BIOS;
+ else
+ viaparinfo->lvds_setting_info->get_lcd_size_method =
+ GET_LCD_SIZE_BY_USER_SETTING;
+
+ viafb_lvds_trasmitter_identify();
+ viafb_init_lcd_size();
+ viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info,
+ viaparinfo->lvds_setting_info);
+ if (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+ viafb_init_lvds_output_interface(&viaparinfo->chip_info->
+ lvds_chip_info2, viaparinfo->lvds_setting_info2);
+ }
+ /*If CX700,two singel LCD, we need to reassign
+ LCD interface to different LVDS port */
+ if ((UNICHROME_CX700 == viaparinfo->chip_info->gfx_chip_name)
+ && (HW_LAYOUT_LCD1_LCD2 == viafb_display_hardware_layout)) {
+ if ((INTEGRATED_LVDS == viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_name) && (INTEGRATED_LVDS ==
+ viaparinfo->chip_info->
+ lvds_chip_info2.lvds_chip_name)) {
+ viaparinfo->chip_info->lvds_chip_info.output_interface =
+ INTERFACE_LVDS0;
+ viaparinfo->chip_info->lvds_chip_info2.
+ output_interface =
+ INTERFACE_LVDS1;
+ }
+ }
+
+ DEBUG_MSG(KERN_INFO "LVDS Chip = %d\n",
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+ DEBUG_MSG(KERN_INFO "LVDS1 output_interface = %d\n",
+ viaparinfo->chip_info->lvds_chip_info.output_interface);
+ DEBUG_MSG(KERN_INFO "LVDS2 output_interface = %d\n",
+ viaparinfo->chip_info->lvds_chip_info.output_interface);
+}
+
+void viafb_init_dac(int set_iga)
+{
+ int i;
+ u8 tmp;
+
+ if (set_iga == IGA1) {
+ /* access Primary Display's LUT */
+ viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0);
+ /* turn off LCK */
+ viafb_write_reg_mask(SR1B, VIASR, 0x00, BIT7 + BIT6);
+ for (i = 0; i < 256; i++) {
+ write_dac_reg(i, palLUT_table[i].red,
+ palLUT_table[i].green,
+ palLUT_table[i].blue);
+ }
+ /* turn on LCK */
+ viafb_write_reg_mask(SR1B, VIASR, 0xC0, BIT7 + BIT6);
+ } else {
+ tmp = viafb_read_reg(VIACR, CR6A);
+ /* access Secondary Display's LUT */
+ viafb_write_reg_mask(CR6A, VIACR, 0x40, BIT6);
+ viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0);
+ for (i = 0; i < 256; i++) {
+ write_dac_reg(i, palLUT_table[i].red,
+ palLUT_table[i].green,
+ palLUT_table[i].blue);
+ }
+ /* set IGA1 DAC for default */
+ viafb_write_reg_mask(SR1A, VIASR, 0x00, BIT0);
+ viafb_write_reg(CR6A, VIACR, tmp);
+ }
+}
+
+static void device_screen_off(void)
+{
+ /* turn off CRT screen (IGA1) */
+ viafb_write_reg_mask(SR01, VIASR, 0x20, BIT5);
+}
+
+static void device_screen_on(void)
+{
+ /* turn on CRT screen (IGA1) */
+ viafb_write_reg_mask(SR01, VIASR, 0x00, BIT5);
+}
+
+static void set_display_channel(void)
+{
+ /*If viafb_LCD2_ON, on cx700, internal lvds's information
+ is keeped on lvds_setting_info2 */
+ if (viafb_LCD2_ON &&
+ viaparinfo->lvds_setting_info2->device_lcd_dualedge) {
+ /* For dual channel LCD: */
+ /* Set to Dual LVDS channel. */
+ viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5);
+ } else if (viafb_LCD_ON && viafb_DVI_ON) {
+ /* For LCD+DFP: */
+ /* Set to LVDS1 + TMDS channel. */
+ viafb_write_reg_mask(CRD2, VIACR, 0x10, BIT4 + BIT5);
+ } else if (viafb_DVI_ON) {
+ /* Set to single TMDS channel. */
+ viafb_write_reg_mask(CRD2, VIACR, 0x30, BIT4 + BIT5);
+ } else if (viafb_LCD_ON) {
+ if (viaparinfo->lvds_setting_info->device_lcd_dualedge) {
+ /* For dual channel LCD: */
+ /* Set to Dual LVDS channel. */
+ viafb_write_reg_mask(CRD2, VIACR, 0x20, BIT4 + BIT5);
+ } else {
+ /* Set to LVDS0 + LVDS1 channel. */
+ viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT4 + BIT5);
+ }
+ }
+}
+
+int viafb_setmode(int vmode_index, int hor_res, int ver_res, int video_bpp,
+ int vmode_index1, int hor_res1, int ver_res1, int video_bpp1)
+{
+ int i, j;
+ int port;
+ u8 value, index, mask;
+ struct VideoModeTable *vmode_tbl;
+ struct crt_mode_table *crt_timing;
+ struct VideoModeTable *vmode_tbl1 = NULL;
+ struct crt_mode_table *crt_timing1 = NULL;
+
+ DEBUG_MSG(KERN_INFO "Set Mode!!\n");
+ DEBUG_MSG(KERN_INFO
+ "vmode_index=%d hor_res=%d ver_res=%d video_bpp=%d\n",
+ vmode_index, hor_res, ver_res, video_bpp);
+
+ device_screen_off();
+ vmode_tbl = &CLE266Modes[search_mode_setting(vmode_index)];
+ crt_timing = vmode_tbl->crtc;
+
+ if (viafb_SAMM_ON == 1) {
+ vmode_tbl1 = &CLE266Modes[search_mode_setting(vmode_index1)];
+ crt_timing1 = vmode_tbl1->crtc;
+ }
+
+ inb(VIAStatus);
+ outb(0x00, VIAAR);
+
+ /* Write Common Setting for Video Mode */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ viafb_write_regx(CLE266_ModeXregs, NUM_TOTAL_CLE266_ModeXregs);
+ break;
+
+ case UNICHROME_K400:
+ viafb_write_regx(KM400_ModeXregs, NUM_TOTAL_KM400_ModeXregs);
+ break;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ viafb_write_regx(CN400_ModeXregs, NUM_TOTAL_CN400_ModeXregs);
+ break;
+
+ case UNICHROME_CN700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ viafb_write_regx(CN700_ModeXregs, NUM_TOTAL_CN700_ModeXregs);
+ break;
+
+ case UNICHROME_CX700:
+ viafb_write_regx(CX700_ModeXregs, NUM_TOTAL_CX700_ModeXregs);
+
+ case UNICHROME_VX800:
+ viafb_write_regx(VX800_ModeXregs, NUM_TOTAL_VX800_ModeXregs);
+
+ break;
+ }
+
+ device_off();
+
+ /* Fill VPIT Parameters */
+ /* Write Misc Register */
+ outb(VPIT.Misc, VIAWMisc);
+
+ /* Write Sequencer */
+ for (i = 1; i <= StdSR; i++) {
+ outb(i, VIASR);
+ outb(VPIT.SR[i - 1], VIASR + 1);
+ }
+
+ viafb_set_start_addr();
+ viafb_set_iga_path();
+
+ /* Write CRTC */
+ viafb_fill_crtc_timing(crt_timing, vmode_index, video_bpp / 8, IGA1);
+
+ /* Write Graphic Controller */
+ for (i = 0; i < StdGR; i++) {
+ outb(i, VIAGR);
+ outb(VPIT.GR[i], VIAGR + 1);
+ }
+
+ /* Write Attribute Controller */
+ for (i = 0; i < StdAR; i++) {
+ inb(VIAStatus);
+ outb(i, VIAAR);
+ outb(VPIT.AR[i], VIAAR);
+ }
+
+ inb(VIAStatus);
+ outb(0x20, VIAAR);
+
+ /* Update Patch Register */
+
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ || (viaparinfo->chip_info->gfx_chip_name == UNICHROME_K400)) {
+ for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
+ if (res_patch_table[i].mode_index == vmode_index) {
+ for (j = 0;
+ j < res_patch_table[i].table_length; j++) {
+ index =
+ res_patch_table[i].
+ io_reg_table[j].index;
+ port =
+ res_patch_table[i].
+ io_reg_table[j].port;
+ value =
+ res_patch_table[i].
+ io_reg_table[j].value;
+ mask =
+ res_patch_table[i].
+ io_reg_table[j].mask;
+ viafb_write_reg_mask(index, port, value,
+ mask);
+ }
+ }
+ }
+ }
+
+ if (viafb_SAMM_ON == 1) {
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)
+ || (viaparinfo->chip_info->gfx_chip_name ==
+ UNICHROME_K400)) {
+ for (i = 0; i < NUM_TOTAL_PATCH_MODE; i++) {
+ if (res_patch_table[i].mode_index ==
+ vmode_index1) {
+ for (j = 0;
+ j <
+ res_patch_table[i].
+ table_length; j++) {
+ index =
+ res_patch_table[i].
+ io_reg_table[j].index;
+ port =
+ res_patch_table[i].
+ io_reg_table[j].port;
+ value =
+ res_patch_table[i].
+ io_reg_table[j].value;
+ mask =
+ res_patch_table[i].
+ io_reg_table[j].mask;
+ viafb_write_reg_mask(index,
+ port, value, mask);
+ }
+ }
+ }
+ }
+ }
+
+ /* Update Refresh Rate Setting */
+
+ /* Clear On Screen */
+
+ /* CRT set mode */
+ if (viafb_CRT_ON) {
+ if (viafb_SAMM_ON && (viaparinfo->crt_setting_info->iga_path ==
+ IGA2)) {
+ viafb_fill_crtc_timing(crt_timing1, vmode_index1,
+ video_bpp1 / 8,
+ viaparinfo->crt_setting_info->iga_path);
+ } else {
+ viafb_fill_crtc_timing(crt_timing, vmode_index,
+ video_bpp / 8,
+ viaparinfo->crt_setting_info->iga_path);
+ }
+
+ set_crt_output_path(viaparinfo->crt_setting_info->iga_path);
+
+ /* Patch if set_hres is not 8 alignment (1366) to viafb_setmode
+ to 8 alignment (1368),there is several pixels (2 pixels)
+ on right side of screen. */
+ if (hor_res % 8) {
+ viafb_unlock_crt();
+ viafb_write_reg(CR02, VIACR,
+ viafb_read_reg(VIACR, CR02) - 1);
+ viafb_lock_crt();
+ }
+ }
+
+ if (viafb_DVI_ON) {
+ if (viafb_SAMM_ON &&
+ (viaparinfo->tmds_setting_info->iga_path == IGA2)) {
+ viafb_dvi_set_mode(viafb_get_mode_index
+ (viaparinfo->tmds_setting_info->h_active,
+ viaparinfo->tmds_setting_info->
+ v_active, 1),
+ video_bpp1, viaparinfo->
+ tmds_setting_info->iga_path);
+ } else {
+ viafb_dvi_set_mode(viafb_get_mode_index
+ (viaparinfo->tmds_setting_info->h_active,
+ viaparinfo->
+ tmds_setting_info->v_active, 0),
+ video_bpp, viaparinfo->
+ tmds_setting_info->iga_path);
+ }
+ }
+
+ if (viafb_LCD_ON) {
+ if (viafb_SAMM_ON &&
+ (viaparinfo->lvds_setting_info->iga_path == IGA2)) {
+ viaparinfo->lvds_setting_info->bpp = video_bpp1;
+ viafb_lcd_set_mode(crt_timing1, viaparinfo->
+ lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ } else {
+ /* IGA1 doesn't have LCD scaling, so set it center. */
+ if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+ viaparinfo->lvds_setting_info->display_method =
+ LCD_CENTERING;
+ }
+ viaparinfo->lvds_setting_info->bpp = video_bpp;
+ viafb_lcd_set_mode(crt_timing, viaparinfo->
+ lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ }
+ }
+ if (viafb_LCD2_ON) {
+ if (viafb_SAMM_ON &&
+ (viaparinfo->lvds_setting_info2->iga_path == IGA2)) {
+ viaparinfo->lvds_setting_info2->bpp = video_bpp1;
+ viafb_lcd_set_mode(crt_timing1, viaparinfo->
+ lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2);
+ } else {
+ /* IGA1 doesn't have LCD scaling, so set it center. */
+ if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
+ viaparinfo->lvds_setting_info2->display_method =
+ LCD_CENTERING;
+ }
+ viaparinfo->lvds_setting_info2->bpp = video_bpp;
+ viafb_lcd_set_mode(crt_timing, viaparinfo->
+ lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2);
+ }
+ }
+
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
+ && (viafb_LCD_ON || viafb_DVI_ON))
+ set_display_channel();
+
+ /* If set mode normally, save resolution information for hot-plug . */
+ if (!viafb_hotplug) {
+ viafb_hotplug_Xres = hor_res;
+ viafb_hotplug_Yres = ver_res;
+ viafb_hotplug_bpp = video_bpp;
+ viafb_hotplug_refresh = viafb_refresh;
+
+ if (viafb_DVI_ON)
+ viafb_DeviceStatus = DVI_Device;
+ else
+ viafb_DeviceStatus = CRT_Device;
+ }
+ device_on();
+
+ if (viafb_SAMM_ON == 1)
+ viafb_write_reg_mask(CR6A, VIACR, 0xC0, BIT6 + BIT7);
+
+ device_screen_on();
+ return 1;
+}
+
+int viafb_get_pixclock(int hres, int vres, int vmode_refresh)
+{
+ int i;
+
+ for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) {
+ if ((hres == res_map_refresh_tbl[i].hres)
+ && (vres == res_map_refresh_tbl[i].vres)
+ && (vmode_refresh == res_map_refresh_tbl[i].vmode_refresh))
+ return res_map_refresh_tbl[i].pixclock;
+ }
+ return RES_640X480_60HZ_PIXCLOCK;
+
+}
+
+int viafb_get_refresh(int hres, int vres, u32 long_refresh)
+{
+#define REFRESH_TOLERANCE 3
+ int i, nearest = -1, diff = REFRESH_TOLERANCE;
+ for (i = 0; i < NUM_TOTAL_RES_MAP_REFRESH; i++) {
+ if ((hres == res_map_refresh_tbl[i].hres)
+ && (vres == res_map_refresh_tbl[i].vres)
+ && (diff > (abs(long_refresh -
+ res_map_refresh_tbl[i].vmode_refresh)))) {
+ diff = abs(long_refresh - res_map_refresh_tbl[i].
+ vmode_refresh);
+ nearest = i;
+ }
+ }
+#undef REFRESH_TOLERANCE
+ if (nearest > 0)
+ return res_map_refresh_tbl[nearest].vmode_refresh;
+ return 60;
+}
+
+static void device_off(void)
+{
+ viafb_crt_disable();
+ viafb_dvi_disable();
+ viafb_lcd_disable();
+}
+
+static void device_on(void)
+{
+ if (viafb_CRT_ON == 1)
+ viafb_crt_enable();
+ if (viafb_DVI_ON == 1)
+ viafb_dvi_enable();
+ if (viafb_LCD_ON == 1)
+ viafb_lcd_enable();
+}
+
+void viafb_crt_disable(void)
+{
+ viafb_write_reg_mask(CR36, VIACR, BIT5 + BIT4, BIT5 + BIT4);
+}
+
+void viafb_crt_enable(void)
+{
+ viafb_write_reg_mask(CR36, VIACR, 0x0, BIT5 + BIT4);
+}
+
+void viafb_get_mmio_info(unsigned long *mmio_base,
+ unsigned long *mmio_len)
+{
+ struct pci_dev *pdev = NULL;
+ u32 vendor, device;
+ u32 i;
+
+ for (i = 0; pciidlist[i].vendor != 0; i++)
+ if (viaparinfo->chip_info->gfx_chip_name ==
+ pciidlist[i].chip_index)
+ break;
+
+ if (!pciidlist[i].vendor)
+ return ;
+
+ vendor = pciidlist[i].vendor;
+ device = pciidlist[i].device;
+
+ pdev = pci_get_device(vendor, device, NULL);
+
+ if (!pdev) {
+ *mmio_base = 0;
+ *mmio_len = 0;
+ return ;
+ }
+
+ *mmio_base = pci_resource_start(pdev, 1);
+ *mmio_len = pci_resource_len(pdev, 1);
+
+ pci_dev_put(pdev);
+}
+
+static void enable_second_display_channel(void)
+{
+ /* to enable second display channel. */
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6);
+ viafb_write_reg_mask(CR6A, VIACR, BIT7, BIT7);
+ viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
+}
+
+static void disable_second_display_channel(void)
+{
+ /* to disable second display channel. */
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT6);
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, BIT7);
+ viafb_write_reg_mask(CR6A, VIACR, BIT6, BIT6);
+}
+
+void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len)
+{
+ struct pci_dev *pdev = NULL;
+ u32 vendor, device;
+ u32 i;
+
+ for (i = 0; pciidlist[i].vendor != 0; i++)
+ if (viaparinfo->chip_info->gfx_chip_name ==
+ pciidlist[i].chip_index)
+ break;
+
+ if (!pciidlist[i].vendor)
+ return ;
+
+ vendor = pciidlist[i].vendor;
+ device = pciidlist[i].device;
+
+ pdev = pci_get_device(vendor, device, NULL);
+
+ if (!pdev) {
+ *fb_base = viafb_read_reg(VIASR, SR30) << 24;
+ *fb_len = viafb_get_memsize();
+ DEBUG_MSG(KERN_INFO "Get FB info from SR30!\n");
+ DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base);
+ DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len);
+ return ;
+ }
+
+ *fb_base = (unsigned int)pci_resource_start(pdev, 0);
+ *fb_len = get_fb_size_from_pci();
+ DEBUG_MSG(KERN_INFO "Get FB info from PCI system!\n");
+ DEBUG_MSG(KERN_INFO "fb_base = %08x\n", *fb_base);
+ DEBUG_MSG(KERN_INFO "fb_len = %08x\n", *fb_len);
+
+ pci_dev_put(pdev);
+}
+
+static int get_fb_size_from_pci(void)
+{
+ unsigned long configid, deviceid, FBSize = 0;
+ int VideoMemSize;
+ int DeviceFound = false;
+
+ for (configid = 0x80000000; configid < 0x80010800; configid += 0x100) {
+ outl(configid, (unsigned long)0xCF8);
+ deviceid = (inl((unsigned long)0xCFC) >> 16) & 0xffff;
+
+ switch (deviceid) {
+ case CLE266:
+ case KM400:
+ outl(configid + 0xE0, (unsigned long)0xCF8);
+ FBSize = inl((unsigned long)0xCFC);
+ DeviceFound = true; /* Found device id */
+ break;
+
+ case CN400_FUNCTION3:
+ case CN700_FUNCTION3:
+ case CX700_FUNCTION3:
+ case KM800_FUNCTION3:
+ case KM890_FUNCTION3:
+ case P4M890_FUNCTION3:
+ case P4M900_FUNCTION3:
+ case VX800_FUNCTION3:
+ /*case CN750_FUNCTION3: */
+ outl(configid + 0xA0, (unsigned long)0xCF8);
+ FBSize = inl((unsigned long)0xCFC);
+ DeviceFound = true; /* Found device id */
+ break;
+
+ default:
+ break;
+ }
+
+ if (DeviceFound)
+ break;
+ }
+
+ DEBUG_MSG(KERN_INFO "Device ID = %lx\n", deviceid);
+
+ FBSize = FBSize & 0x00007000;
+ DEBUG_MSG(KERN_INFO "FB Size = %x\n", FBSize);
+
+ if (viaparinfo->chip_info->gfx_chip_name < UNICHROME_CX700) {
+ switch (FBSize) {
+ case 0x00004000:
+ VideoMemSize = (16 << 20); /*16M */
+ break;
+
+ case 0x00005000:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+
+ case 0x00006000:
+ VideoMemSize = (64 << 20); /*64M */
+ break;
+
+ default:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+ }
+ } else {
+ switch (FBSize) {
+ case 0x00001000:
+ VideoMemSize = (8 << 20); /*8M */
+ break;
+
+ case 0x00002000:
+ VideoMemSize = (16 << 20); /*16M */
+ break;
+
+ case 0x00003000:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+
+ case 0x00004000:
+ VideoMemSize = (64 << 20); /*64M */
+ break;
+
+ case 0x00005000:
+ VideoMemSize = (128 << 20); /*128M */
+ break;
+
+ case 0x00006000:
+ VideoMemSize = (256 << 20); /*256M */
+ break;
+
+ default:
+ VideoMemSize = (32 << 20); /*32M */
+ break;
+ }
+ }
+
+ return VideoMemSize;
+}
+
+void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
+ *p_gfx_dpa_setting)
+{
+ switch (output_interface) {
+ case INTERFACE_DVP0:
+ {
+ /* DVP0 Clock Polarity and Adjust: */
+ viafb_write_reg_mask(CR96, VIACR,
+ p_gfx_dpa_setting->DVP0, 0x0F);
+
+ /* DVP0 Clock and Data Pads Driving: */
+ viafb_write_reg_mask(SR1E, VIASR,
+ p_gfx_dpa_setting->DVP0ClockDri_S, BIT2);
+ viafb_write_reg_mask(SR2A, VIASR,
+ p_gfx_dpa_setting->DVP0ClockDri_S1,
+ BIT4);
+ viafb_write_reg_mask(SR1B, VIASR,
+ p_gfx_dpa_setting->DVP0DataDri_S, BIT1);
+ viafb_write_reg_mask(SR2A, VIASR,
+ p_gfx_dpa_setting->DVP0DataDri_S1, BIT5);
+ break;
+ }
+
+ case INTERFACE_DVP1:
+ {
+ /* DVP1 Clock Polarity and Adjust: */
+ viafb_write_reg_mask(CR9B, VIACR,
+ p_gfx_dpa_setting->DVP1, 0x0F);
+
+ /* DVP1 Clock and Data Pads Driving: */
+ viafb_write_reg_mask(SR65, VIASR,
+ p_gfx_dpa_setting->DVP1Driving, 0x0F);
+ break;
+ }
+
+ case INTERFACE_DFP_HIGH:
+ {
+ viafb_write_reg_mask(CR97, VIACR,
+ p_gfx_dpa_setting->DFPHigh, 0x0F);
+ break;
+ }
+
+ case INTERFACE_DFP_LOW:
+ {
+ viafb_write_reg_mask(CR99, VIACR,
+ p_gfx_dpa_setting->DFPLow, 0x0F);
+ break;
+ }
+
+ case INTERFACE_DFP:
+ {
+ viafb_write_reg_mask(CR97, VIACR,
+ p_gfx_dpa_setting->DFPHigh, 0x0F);
+ viafb_write_reg_mask(CR99, VIACR,
+ p_gfx_dpa_setting->DFPLow, 0x0F);
+ break;
+ }
+ }
+}
+
+void viafb_memory_pitch_patch(struct fb_info *info)
+{
+ if (info->var.xres != info->var.xres_virtual) {
+ viafb_load_offset_reg(info->var.xres_virtual,
+ info->var.bits_per_pixel >> 3, IGA1);
+
+ if (viafb_SAMM_ON) {
+ viafb_load_offset_reg(viafb_second_virtual_xres,
+ viafb_bpp1 >> 3,
+ IGA2);
+ } else {
+ viafb_load_offset_reg(info->var.xres_virtual,
+ info->var.bits_per_pixel >> 3, IGA2);
+ }
+
+ }
+}
+
+/*According var's xres, yres fill var's other timing information*/
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+ int mode_index)
+{
+ struct VideoModeTable *vmode_tbl = NULL;
+ struct crt_mode_table *crt_timing = NULL;
+ struct display_timing crt_reg;
+ int i = 0, index = 0;
+ vmode_tbl = &CLE266Modes[search_mode_setting(mode_index)];
+ crt_timing = vmode_tbl->crtc;
+ for (i = 0; i < vmode_tbl->mode_array; i++) {
+ index = i;
+ if (crt_timing[i].refresh_rate == refresh)
+ break;
+ }
+
+ crt_reg = crt_timing[index].crtc;
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.offset = 0;
+ var->green.offset = 0;
+ var->blue.offset = 0;
+ var->red.length = 6;
+ var->green.length = 6;
+ var->blue.length = 6;
+ break;
+ case 16:
+ var->red.offset = 11;
+ var->green.offset = 5;
+ var->blue.offset = 0;
+ var->red.length = 5;
+ var->green.length = 6;
+ var->blue.length = 5;
+ break;
+ case 32:
+ var->red.offset = 16;
+ var->green.offset = 8;
+ var->blue.offset = 0;
+ var->red.length = 8;
+ var->green.length = 8;
+ var->blue.length = 8;
+ break;
+ default:
+ /* never happed, put here to keep consistent */
+ break;
+ }
+
+ var->pixclock = viafb_get_pixclock(var->xres, var->yres, refresh);
+ var->left_margin =
+ crt_reg.hor_total - (crt_reg.hor_sync_start + crt_reg.hor_sync_end);
+ var->right_margin = crt_reg.hor_sync_start - crt_reg.hor_addr;
+ var->hsync_len = crt_reg.hor_sync_end;
+ var->upper_margin =
+ crt_reg.ver_total - (crt_reg.ver_sync_start + crt_reg.ver_sync_end);
+ var->lower_margin = crt_reg.ver_sync_start - crt_reg.ver_addr;
+ var->vsync_len = crt_reg.ver_sync_end;
+}
diff --git a/drivers/video/via/hw.h b/drivers/video/via/hw.h
new file mode 100644
index 00000000000..6ff38fa8569
--- /dev/null
+++ b/drivers/video/via/hw.h
@@ -0,0 +1,933 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __HW_H__
+#define __HW_H__
+
+#include "global.h"
+
+/***************************************************
+* Definition IGA1 Design Method of CRTC Registers *
+****************************************************/
+#define IGA1_HOR_TOTAL_FORMULA(x) (((x)/8)-5)
+#define IGA1_HOR_ADDR_FORMULA(x) (((x)/8)-1)
+#define IGA1_HOR_BLANK_START_FORMULA(x) (((x)/8)-1)
+#define IGA1_HOR_BLANK_END_FORMULA(x, y) (((x+y)/8)-1)
+#define IGA1_HOR_SYNC_START_FORMULA(x) ((x)/8)
+#define IGA1_HOR_SYNC_END_FORMULA(x, y) ((x+y)/8)
+
+#define IGA1_VER_TOTAL_FORMULA(x) ((x)-2)
+#define IGA1_VER_ADDR_FORMULA(x) ((x)-1)
+#define IGA1_VER_BLANK_START_FORMULA(x) ((x)-1)
+#define IGA1_VER_BLANK_END_FORMULA(x, y) ((x+y)-1)
+#define IGA1_VER_SYNC_START_FORMULA(x) ((x)-1)
+#define IGA1_VER_SYNC_END_FORMULA(x, y) ((x+y)-1)
+
+/***************************************************
+** Definition IGA2 Design Method of CRTC Registers *
+****************************************************/
+#define IGA2_HOR_TOTAL_FORMULA(x) ((x)-1)
+#define IGA2_HOR_ADDR_FORMULA(x) ((x)-1)
+#define IGA2_HOR_BLANK_START_FORMULA(x) ((x)-1)
+#define IGA2_HOR_BLANK_END_FORMULA(x, y) ((x+y)-1)
+#define IGA2_HOR_SYNC_START_FORMULA(x) ((x)-1)
+#define IGA2_HOR_SYNC_END_FORMULA(x, y) ((x+y)-1)
+
+#define IGA2_VER_TOTAL_FORMULA(x) ((x)-1)
+#define IGA2_VER_ADDR_FORMULA(x) ((x)-1)
+#define IGA2_VER_BLANK_START_FORMULA(x) ((x)-1)
+#define IGA2_VER_BLANK_END_FORMULA(x, y) ((x+y)-1)
+#define IGA2_VER_SYNC_START_FORMULA(x) ((x)-1)
+#define IGA2_VER_SYNC_END_FORMULA(x, y) ((x+y)-1)
+
+/**********************************************************/
+/* Definition IGA2 Design Method of CRTC Shadow Registers */
+/**********************************************************/
+#define IGA2_HOR_TOTAL_SHADOW_FORMULA(x) ((x/8)-5)
+#define IGA2_HOR_BLANK_END_SHADOW_FORMULA(x, y) (((x+y)/8)-1)
+#define IGA2_VER_TOTAL_SHADOW_FORMULA(x) ((x)-2)
+#define IGA2_VER_ADDR_SHADOW_FORMULA(x) ((x)-1)
+#define IGA2_VER_BLANK_START_SHADOW_FORMULA(x) ((x)-1)
+#define IGA2_VER_BLANK_END_SHADOW_FORMULA(x, y) ((x+y)-1)
+#define IGA2_VER_SYNC_START_SHADOW_FORMULA(x) (x)
+#define IGA2_VER_SYNC_END_SHADOW_FORMULA(x, y) (x+y)
+
+/* Define Register Number for IGA1 CRTC Timing */
+
+/* location: {CR00,0,7},{CR36,3,3} */
+#define IGA1_HOR_TOTAL_REG_NUM 2
+/* location: {CR01,0,7} */
+#define IGA1_HOR_ADDR_REG_NUM 1
+/* location: {CR02,0,7} */
+#define IGA1_HOR_BLANK_START_REG_NUM 1
+/* location: {CR03,0,4},{CR05,7,7},{CR33,5,5} */
+#define IGA1_HOR_BLANK_END_REG_NUM 3
+/* location: {CR04,0,7},{CR33,4,4} */
+#define IGA1_HOR_SYNC_START_REG_NUM 2
+/* location: {CR05,0,4} */
+#define IGA1_HOR_SYNC_END_REG_NUM 1
+/* location: {CR06,0,7},{CR07,0,0},{CR07,5,5},{CR35,0,0} */
+#define IGA1_VER_TOTAL_REG_NUM 4
+/* location: {CR12,0,7},{CR07,1,1},{CR07,6,6},{CR35,2,2} */
+#define IGA1_VER_ADDR_REG_NUM 4
+/* location: {CR15,0,7},{CR07,3,3},{CR09,5,5},{CR35,3,3} */
+#define IGA1_VER_BLANK_START_REG_NUM 4
+/* location: {CR16,0,7} */
+#define IGA1_VER_BLANK_END_REG_NUM 1
+/* location: {CR10,0,7},{CR07,2,2},{CR07,7,7},{CR35,1,1} */
+#define IGA1_VER_SYNC_START_REG_NUM 4
+/* location: {CR11,0,3} */
+#define IGA1_VER_SYNC_END_REG_NUM 1
+
+/* Define Register Number for IGA2 Shadow CRTC Timing */
+
+/* location: {CR6D,0,7},{CR71,3,3} */
+#define IGA2_SHADOW_HOR_TOTAL_REG_NUM 2
+/* location: {CR6E,0,7} */
+#define IGA2_SHADOW_HOR_BLANK_END_REG_NUM 1
+/* location: {CR6F,0,7},{CR71,0,2} */
+#define IGA2_SHADOW_VER_TOTAL_REG_NUM 2
+/* location: {CR70,0,7},{CR71,4,6} */
+#define IGA2_SHADOW_VER_ADDR_REG_NUM 2
+/* location: {CR72,0,7},{CR74,4,6} */
+#define IGA2_SHADOW_VER_BLANK_START_REG_NUM 2
+/* location: {CR73,0,7},{CR74,0,2} */
+#define IGA2_SHADOW_VER_BLANK_END_REG_NUM 2
+/* location: {CR75,0,7},{CR76,4,6} */
+#define IGA2_SHADOW_VER_SYNC_START_REG_NUM 2
+/* location: {CR76,0,3} */
+#define IGA2_SHADOW_VER_SYNC_END_REG_NUM 1
+
+/* Define Register Number for IGA2 CRTC Timing */
+
+/* location: {CR50,0,7},{CR55,0,3} */
+#define IGA2_HOR_TOTAL_REG_NUM 2
+/* location: {CR51,0,7},{CR55,4,6} */
+#define IGA2_HOR_ADDR_REG_NUM 2
+/* location: {CR52,0,7},{CR54,0,2} */
+#define IGA2_HOR_BLANK_START_REG_NUM 2
+/* location: CLE266: {CR53,0,7},{CR54,3,5} => CLE266's CR5D[6]
+is reserved, so it may have problem to set 1600x1200 on IGA2. */
+/* Others: {CR53,0,7},{CR54,3,5},{CR5D,6,6} */
+#define IGA2_HOR_BLANK_END_REG_NUM 3
+/* location: {CR56,0,7},{CR54,6,7},{CR5C,7,7} */
+/* VT3314 and Later: {CR56,0,7},{CR54,6,7},{CR5C,7,7}, {CR5D,7,7} */
+#define IGA2_HOR_SYNC_START_REG_NUM 4
+
+/* location: {CR57,0,7},{CR5C,6,6} */
+#define IGA2_HOR_SYNC_END_REG_NUM 2
+/* location: {CR58,0,7},{CR5D,0,2} */
+#define IGA2_VER_TOTAL_REG_NUM 2
+/* location: {CR59,0,7},{CR5D,3,5} */
+#define IGA2_VER_ADDR_REG_NUM 2
+/* location: {CR5A,0,7},{CR5C,0,2} */
+#define IGA2_VER_BLANK_START_REG_NUM 2
+/* location: {CR5E,0,7},{CR5C,3,5} */
+#define IGA2_VER_BLANK_END_REG_NUM 2
+/* location: {CR5E,0,7},{CR5F,5,7} */
+#define IGA2_VER_SYNC_START_REG_NUM 2
+/* location: {CR5F,0,4} */
+#define IGA2_VER_SYNC_END_REG_NUM 1
+
+/* Define Offset and Fetch Count Register*/
+
+/* location: {CR13,0,7},{CR35,5,7} */
+#define IGA1_OFFSET_REG_NUM 2
+/* 8 bytes alignment. */
+#define IGA1_OFFSER_ALIGN_BYTE 8
+/* x: H resolution, y: color depth */
+#define IGA1_OFFSET_FORMULA(x, y) ((x*y)/IGA1_OFFSER_ALIGN_BYTE)
+/* location: {SR1C,0,7},{SR1D,0,1} */
+#define IGA1_FETCH_COUNT_REG_NUM 2
+/* 16 bytes alignment. */
+#define IGA1_FETCH_COUNT_ALIGN_BYTE 16
+/* x: H resolution, y: color depth */
+#define IGA1_FETCH_COUNT_PATCH_VALUE 4
+#define IGA1_FETCH_COUNT_FORMULA(x, y) \
+ (((x*y)/IGA1_FETCH_COUNT_ALIGN_BYTE) + IGA1_FETCH_COUNT_PATCH_VALUE)
+
+/* location: {CR66,0,7},{CR67,0,1} */
+#define IGA2_OFFSET_REG_NUM 2
+#define IGA2_OFFSET_ALIGN_BYTE 8
+/* x: H resolution, y: color depth */
+#define IGA2_OFFSET_FORMULA(x, y) ((x*y)/IGA2_OFFSET_ALIGN_BYTE)
+/* location: {CR65,0,7},{CR67,2,3} */
+#define IGA2_FETCH_COUNT_REG_NUM 2
+#define IGA2_FETCH_COUNT_ALIGN_BYTE 16
+#define IGA2_FETCH_COUNT_PATCH_VALUE 0
+#define IGA2_FETCH_COUNT_FORMULA(x, y) \
+ (((x*y)/IGA2_FETCH_COUNT_ALIGN_BYTE) + IGA2_FETCH_COUNT_PATCH_VALUE)
+
+/* Staring Address*/
+
+/* location: {CR0C,0,7},{CR0D,0,7},{CR34,0,7},{CR48,0,1} */
+#define IGA1_STARTING_ADDR_REG_NUM 4
+/* location: {CR62,1,7},{CR63,0,7},{CR64,0,7} */
+#define IGA2_STARTING_ADDR_REG_NUM 3
+
+/* Define Display OFFSET*/
+/* These value are by HW suggested value*/
+/* location: {SR17,0,7} */
+#define K800_IGA1_FIFO_MAX_DEPTH 384
+/* location: {SR16,0,5},{SR16,7,7} */
+#define K800_IGA1_FIFO_THRESHOLD 328
+/* location: {SR18,0,5},{SR18,7,7} */
+#define K800_IGA1_FIFO_HIGH_THRESHOLD 296
+/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */
+ /* because HW only 5 bits */
+#define K800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define K800_IGA2_FIFO_MAX_DEPTH 384
+/* location: {CR68,0,3},{CR95,4,6} */
+#define K800_IGA2_FIFO_THRESHOLD 328
+/* location: {CR92,0,3},{CR95,0,2} */
+#define K800_IGA2_FIFO_HIGH_THRESHOLD 296
+/* location: {CR94,0,6} */
+#define K800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128
+
+/* location: {SR17,0,7} */
+#define P880_IGA1_FIFO_MAX_DEPTH 192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P880_IGA1_FIFO_THRESHOLD 128
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P880_IGA1_FIFO_HIGH_THRESHOLD 64
+/* location: {SR22,0,4}. (128/4) =64, K800 must be set zero, */
+ /* because HW only 5 bits */
+#define P880_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P880_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P880_IGA2_FIFO_THRESHOLD 64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P880_IGA2_FIFO_HIGH_THRESHOLD 32
+/* location: {CR94,0,6} */
+#define P880_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128
+
+/* VT3314 chipset*/
+
+/* location: {SR17,0,7} */
+#define CN700_IGA1_FIFO_MAX_DEPTH 96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define CN700_IGA1_FIFO_THRESHOLD 80
+/* location: {SR18,0,5},{SR18,7,7} */
+#define CN700_IGA1_FIFO_HIGH_THRESHOLD 64
+/* location: {SR22,0,4}. (128/4) =64, P800 must be set zero,
+ because HW only 5 bits */
+#define CN700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 0
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define CN700_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define CN700_IGA2_FIFO_THRESHOLD 80
+/* location: {CR92,0,3},{CR95,0,2} */
+#define CN700_IGA2_FIFO_HIGH_THRESHOLD 32
+/* location: {CR94,0,6} */
+#define CN700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128
+
+/* For VT3324, these values are suggested by HW */
+/* location: {SR17,0,7} */
+#define CX700_IGA1_FIFO_MAX_DEPTH 192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define CX700_IGA1_FIFO_THRESHOLD 128
+/* location: {SR18,0,5},{SR18,7,7} */
+#define CX700_IGA1_FIFO_HIGH_THRESHOLD 128
+/* location: {SR22,0,4} */
+#define CX700_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define CX700_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define CX700_IGA2_FIFO_THRESHOLD 64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define CX700_IGA2_FIFO_HIGH_THRESHOLD 32
+/* location: {CR94,0,6} */
+#define CX700_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128
+
+/* VT3336 chipset*/
+/* location: {SR17,0,7} */
+#define K8M890_IGA1_FIFO_MAX_DEPTH 360
+/* location: {SR16,0,5},{SR16,7,7} */
+#define K8M890_IGA1_FIFO_THRESHOLD 328
+/* location: {SR18,0,5},{SR18,7,7} */
+#define K8M890_IGA1_FIFO_HIGH_THRESHOLD 296
+/* location: {SR22,0,4}. */
+#define K8M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 124
+
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define K8M890_IGA2_FIFO_MAX_DEPTH 360
+/* location: {CR68,0,3},{CR95,4,6} */
+#define K8M890_IGA2_FIFO_THRESHOLD 328
+/* location: {CR92,0,3},{CR95,0,2} */
+#define K8M890_IGA2_FIFO_HIGH_THRESHOLD 296
+/* location: {CR94,0,6} */
+#define K8M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 124
+
+/* VT3327 chipset*/
+/* location: {SR17,0,7} */
+#define P4M890_IGA1_FIFO_MAX_DEPTH 96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P4M890_IGA1_FIFO_THRESHOLD 76
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P4M890_IGA1_FIFO_HIGH_THRESHOLD 64
+/* location: {SR22,0,4}. (32/4) =8 */
+#define P4M890_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P4M890_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P4M890_IGA2_FIFO_THRESHOLD 76
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P4M890_IGA2_FIFO_HIGH_THRESHOLD 64
+/* location: {CR94,0,6} */
+#define P4M890_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32
+
+/* VT3364 chipset*/
+/* location: {SR17,0,7} */
+#define P4M900_IGA1_FIFO_MAX_DEPTH 96
+/* location: {SR16,0,5},{SR16,7,7} */
+#define P4M900_IGA1_FIFO_THRESHOLD 76
+/* location: {SR18,0,5},{SR18,7,7} */
+#define P4M900_IGA1_FIFO_HIGH_THRESHOLD 76
+/* location: {SR22,0,4}. */
+#define P4M900_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 32
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define P4M900_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define P4M900_IGA2_FIFO_THRESHOLD 76
+/* location: {CR92,0,3},{CR95,0,2} */
+#define P4M900_IGA2_FIFO_HIGH_THRESHOLD 76
+/* location: {CR94,0,6} */
+#define P4M900_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 32
+
+/* For VT3353, these values are suggested by HW */
+/* location: {SR17,0,7} */
+#define VX800_IGA1_FIFO_MAX_DEPTH 192
+/* location: {SR16,0,5},{SR16,7,7} */
+#define VX800_IGA1_FIFO_THRESHOLD 152
+/* location: {SR18,0,5},{SR18,7,7} */
+#define VX800_IGA1_FIFO_HIGH_THRESHOLD 152
+/* location: {SR22,0,4} */
+#define VX800_IGA1_DISPLAY_QUEUE_EXPIRE_NUM 64
+/* location: {CR68,4,7},{CR94,7,7},{CR95,7,7} */
+#define VX800_IGA2_FIFO_MAX_DEPTH 96
+/* location: {CR68,0,3},{CR95,4,6} */
+#define VX800_IGA2_FIFO_THRESHOLD 64
+/* location: {CR92,0,3},{CR95,0,2} */
+#define VX800_IGA2_FIFO_HIGH_THRESHOLD 32
+/* location: {CR94,0,6} */
+#define VX800_IGA2_DISPLAY_QUEUE_EXPIRE_NUM 128
+
+#define IGA1_FIFO_DEPTH_SELECT_REG_NUM 1
+#define IGA1_FIFO_THRESHOLD_REG_NUM 2
+#define IGA1_FIFO_HIGH_THRESHOLD_REG_NUM 2
+#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1
+
+#define IGA2_FIFO_DEPTH_SELECT_REG_NUM 3
+#define IGA2_FIFO_THRESHOLD_REG_NUM 2
+#define IGA2_FIFO_HIGH_THRESHOLD_REG_NUM 2
+#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM 1
+
+#define IGA1_FIFO_DEPTH_SELECT_FORMULA(x) ((x/2)-1)
+#define IGA1_FIFO_THRESHOLD_FORMULA(x) (x/4)
+#define IGA1_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4)
+#define IGA1_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4)
+#define IGA2_FIFO_DEPTH_SELECT_FORMULA(x) (((x/2)/4)-1)
+#define IGA2_FIFO_THRESHOLD_FORMULA(x) (x/4)
+#define IGA2_DISPLAY_QUEUE_EXPIRE_NUM_FORMULA(x) (x/4)
+#define IGA2_FIFO_HIGH_THRESHOLD_FORMULA(x) (x/4)
+
+/************************************************************************/
+/* LCD Timing */
+/************************************************************************/
+
+/* 500 ms = 500000 us */
+#define LCD_POWER_SEQ_TD0 500000
+/* 50 ms = 50000 us */
+#define LCD_POWER_SEQ_TD1 50000
+/* 0 us */
+#define LCD_POWER_SEQ_TD2 0
+/* 210 ms = 210000 us */
+#define LCD_POWER_SEQ_TD3 210000
+/* 2^10 * (1/14.31818M) = 71.475 us (K400.revA) */
+#define CLE266_POWER_SEQ_UNIT 71
+/* 2^11 * (1/14.31818M) = 142.95 us (K400.revB) */
+#define K800_POWER_SEQ_UNIT 142
+/* 2^13 * (1/14.31818M) = 572.1 us */
+#define P880_POWER_SEQ_UNIT 572
+
+#define CLE266_POWER_SEQ_FORMULA(x) ((x)/CLE266_POWER_SEQ_UNIT)
+#define K800_POWER_SEQ_FORMULA(x) ((x)/K800_POWER_SEQ_UNIT)
+#define P880_POWER_SEQ_FORMULA(x) ((x)/P880_POWER_SEQ_UNIT)
+
+/* location: {CR8B,0,7},{CR8F,0,3} */
+#define LCD_POWER_SEQ_TD0_REG_NUM 2
+/* location: {CR8C,0,7},{CR8F,4,7} */
+#define LCD_POWER_SEQ_TD1_REG_NUM 2
+/* location: {CR8D,0,7},{CR90,0,3} */
+#define LCD_POWER_SEQ_TD2_REG_NUM 2
+/* location: {CR8E,0,7},{CR90,4,7} */
+#define LCD_POWER_SEQ_TD3_REG_NUM 2
+
+/* LCD Scaling factor*/
+/* x: indicate setting horizontal size*/
+/* y: indicate panel horizontal size*/
+
+/* Horizontal scaling factor 10 bits (2^10) */
+#define CLE266_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1))
+/* Vertical scaling factor 10 bits (2^10) */
+#define CLE266_LCD_VER_SCF_FORMULA(x, y) (((x-1)*1024)/(y-1))
+/* Horizontal scaling factor 10 bits (2^12) */
+#define K800_LCD_HOR_SCF_FORMULA(x, y) (((x-1)*4096)/(y-1))
+/* Vertical scaling factor 10 bits (2^11) */
+#define K800_LCD_VER_SCF_FORMULA(x, y) (((x-1)*2048)/(y-1))
+
+/* location: {CR9F,0,1},{CR77,0,7},{CR79,4,5} */
+#define LCD_HOR_SCALING_FACTOR_REG_NUM 3
+/* location: {CR79,3,3},{CR78,0,7},{CR79,6,7} */
+#define LCD_VER_SCALING_FACTOR_REG_NUM 3
+/* location: {CR77,0,7},{CR79,4,5} */
+#define LCD_HOR_SCALING_FACTOR_REG_NUM_CLE 2
+/* location: {CR78,0,7},{CR79,6,7} */
+#define LCD_VER_SCALING_FACTOR_REG_NUM_CLE 2
+
+/************************************************
+ ***** Define IGA1 Display Timing *****
+ ************************************************/
+struct io_register {
+ u8 io_addr;
+ u8 start_bit;
+ u8 end_bit;
+};
+
+/* IGA1 Horizontal Total */
+struct iga1_hor_total {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA1 Horizontal Addressable Video */
+struct iga1_hor_addr {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_ADDR_REG_NUM];
+};
+
+/* IGA1 Horizontal Blank Start */
+struct iga1_hor_blank_start {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_BLANK_START_REG_NUM];
+};
+
+/* IGA1 Horizontal Blank End */
+struct iga1_hor_blank_end {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA1 Horizontal Sync Start */
+struct iga1_hor_sync_start {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_SYNC_START_REG_NUM];
+};
+
+/* IGA1 Horizontal Sync End */
+struct iga1_hor_sync_end {
+ int reg_num;
+ struct io_register reg[IGA1_HOR_SYNC_END_REG_NUM];
+};
+
+/* IGA1 Vertical Total */
+struct iga1_ver_total {
+ int reg_num;
+ struct io_register reg[IGA1_VER_TOTAL_REG_NUM];
+};
+
+/* IGA1 Vertical Addressable Video */
+struct iga1_ver_addr {
+ int reg_num;
+ struct io_register reg[IGA1_VER_ADDR_REG_NUM];
+};
+
+/* IGA1 Vertical Blank Start */
+struct iga1_ver_blank_start {
+ int reg_num;
+ struct io_register reg[IGA1_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA1 Vertical Blank End */
+struct iga1_ver_blank_end {
+ int reg_num;
+ struct io_register reg[IGA1_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA1 Vertical Sync Start */
+struct iga1_ver_sync_start {
+ int reg_num;
+ struct io_register reg[IGA1_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA1 Vertical Sync End */
+struct iga1_ver_sync_end {
+ int reg_num;
+ struct io_register reg[IGA1_VER_SYNC_END_REG_NUM];
+};
+
+/*****************************************************
+** Define IGA2 Shadow Display Timing ****
+*****************************************************/
+
+/* IGA2 Shadow Horizontal Total */
+struct iga2_shadow_hor_total {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA2 Shadow Horizontal Blank End */
+struct iga2_shadow_hor_blank_end {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Total */
+struct iga2_shadow_ver_total {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_TOTAL_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Addressable Video */
+struct iga2_shadow_ver_addr {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_ADDR_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Blank Start */
+struct iga2_shadow_ver_blank_start {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Blank End */
+struct iga2_shadow_ver_blank_end {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Sync Start */
+struct iga2_shadow_ver_sync_start {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Shadow Vertical Sync End */
+struct iga2_shadow_ver_sync_end {
+ int reg_num;
+ struct io_register reg[IGA2_SHADOW_VER_SYNC_END_REG_NUM];
+};
+
+/*****************************************************
+** Define IGA2 Display Timing ****
+******************************************************/
+
+/* IGA2 Horizontal Total */
+struct iga2_hor_total {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_TOTAL_REG_NUM];
+};
+
+/* IGA2 Horizontal Addressable Video */
+struct iga2_hor_addr {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_ADDR_REG_NUM];
+};
+
+/* IGA2 Horizontal Blank Start */
+struct iga2_hor_blank_start {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Horizontal Blank End */
+struct iga2_hor_blank_end {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Horizontal Sync Start */
+struct iga2_hor_sync_start {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Horizontal Sync End */
+struct iga2_hor_sync_end {
+ int reg_num;
+ struct io_register reg[IGA2_HOR_SYNC_END_REG_NUM];
+};
+
+/* IGA2 Vertical Total */
+struct iga2_ver_total {
+ int reg_num;
+ struct io_register reg[IGA2_VER_TOTAL_REG_NUM];
+};
+
+/* IGA2 Vertical Addressable Video */
+struct iga2_ver_addr {
+ int reg_num;
+ struct io_register reg[IGA2_VER_ADDR_REG_NUM];
+};
+
+/* IGA2 Vertical Blank Start */
+struct iga2_ver_blank_start {
+ int reg_num;
+ struct io_register reg[IGA2_VER_BLANK_START_REG_NUM];
+};
+
+/* IGA2 Vertical Blank End */
+struct iga2_ver_blank_end {
+ int reg_num;
+ struct io_register reg[IGA2_VER_BLANK_END_REG_NUM];
+};
+
+/* IGA2 Vertical Sync Start */
+struct iga2_ver_sync_start {
+ int reg_num;
+ struct io_register reg[IGA2_VER_SYNC_START_REG_NUM];
+};
+
+/* IGA2 Vertical Sync End */
+struct iga2_ver_sync_end {
+ int reg_num;
+ struct io_register reg[IGA2_VER_SYNC_END_REG_NUM];
+};
+
+/* IGA1 Offset Register */
+struct iga1_offset {
+ int reg_num;
+ struct io_register reg[IGA1_OFFSET_REG_NUM];
+};
+
+/* IGA2 Offset Register */
+struct iga2_offset {
+ int reg_num;
+ struct io_register reg[IGA2_OFFSET_REG_NUM];
+};
+
+struct offset {
+ struct iga1_offset iga1_offset_reg;
+ struct iga2_offset iga2_offset_reg;
+};
+
+/* IGA1 Fetch Count Register */
+struct iga1_fetch_count {
+ int reg_num;
+ struct io_register reg[IGA1_FETCH_COUNT_REG_NUM];
+};
+
+/* IGA2 Fetch Count Register */
+struct iga2_fetch_count {
+ int reg_num;
+ struct io_register reg[IGA2_FETCH_COUNT_REG_NUM];
+};
+
+struct fetch_count {
+ struct iga1_fetch_count iga1_fetch_count_reg;
+ struct iga2_fetch_count iga2_fetch_count_reg;
+};
+
+/* Starting Address Register */
+struct iga1_starting_addr {
+ int reg_num;
+ struct io_register reg[IGA1_STARTING_ADDR_REG_NUM];
+};
+
+struct iga2_starting_addr {
+ int reg_num;
+ struct io_register reg[IGA2_STARTING_ADDR_REG_NUM];
+};
+
+struct starting_addr {
+ struct iga1_starting_addr iga1_starting_addr_reg;
+ struct iga2_starting_addr iga2_starting_addr_reg;
+};
+
+/* LCD Power Sequence Timer */
+struct lcd_pwd_seq_td0 {
+ int reg_num;
+ struct io_register reg[LCD_POWER_SEQ_TD0_REG_NUM];
+};
+
+struct lcd_pwd_seq_td1 {
+ int reg_num;
+ struct io_register reg[LCD_POWER_SEQ_TD1_REG_NUM];
+};
+
+struct lcd_pwd_seq_td2 {
+ int reg_num;
+ struct io_register reg[LCD_POWER_SEQ_TD2_REG_NUM];
+};
+
+struct lcd_pwd_seq_td3 {
+ int reg_num;
+ struct io_register reg[LCD_POWER_SEQ_TD3_REG_NUM];
+};
+
+struct _lcd_pwd_seq_timer {
+ struct lcd_pwd_seq_td0 td0;
+ struct lcd_pwd_seq_td1 td1;
+ struct lcd_pwd_seq_td2 td2;
+ struct lcd_pwd_seq_td3 td3;
+};
+
+/* LCD Scaling Factor */
+struct _lcd_hor_scaling_factor {
+ int reg_num;
+ struct io_register reg[LCD_HOR_SCALING_FACTOR_REG_NUM];
+};
+
+struct _lcd_ver_scaling_factor {
+ int reg_num;
+ struct io_register reg[LCD_VER_SCALING_FACTOR_REG_NUM];
+};
+
+struct _lcd_scaling_factor {
+ struct _lcd_hor_scaling_factor lcd_hor_scaling_factor;
+ struct _lcd_ver_scaling_factor lcd_ver_scaling_factor;
+};
+
+struct pll_map {
+ u32 clk;
+ u32 cle266_pll;
+ u32 k800_pll;
+ u32 cx700_pll;
+};
+
+struct rgbLUT {
+ u8 red;
+ u8 green;
+ u8 blue;
+};
+
+struct lcd_pwd_seq_timer {
+ u16 td0;
+ u16 td1;
+ u16 td2;
+ u16 td3;
+};
+
+/* Display FIFO Relation Registers*/
+struct iga1_fifo_depth_select {
+ int reg_num;
+ struct io_register reg[IGA1_FIFO_DEPTH_SELECT_REG_NUM];
+};
+
+struct iga1_fifo_threshold_select {
+ int reg_num;
+ struct io_register reg[IGA1_FIFO_THRESHOLD_REG_NUM];
+};
+
+struct iga1_fifo_high_threshold_select {
+ int reg_num;
+ struct io_register reg[IGA1_FIFO_HIGH_THRESHOLD_REG_NUM];
+};
+
+struct iga1_display_queue_expire_num {
+ int reg_num;
+ struct io_register reg[IGA1_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM];
+};
+
+struct iga2_fifo_depth_select {
+ int reg_num;
+ struct io_register reg[IGA2_FIFO_DEPTH_SELECT_REG_NUM];
+};
+
+struct iga2_fifo_threshold_select {
+ int reg_num;
+ struct io_register reg[IGA2_FIFO_THRESHOLD_REG_NUM];
+};
+
+struct iga2_fifo_high_threshold_select {
+ int reg_num;
+ struct io_register reg[IGA2_FIFO_HIGH_THRESHOLD_REG_NUM];
+};
+
+struct iga2_display_queue_expire_num {
+ int reg_num;
+ struct io_register reg[IGA2_DISPLAY_QUEUE_EXPIRE_NUM_REG_NUM];
+};
+
+struct fifo_depth_select {
+ struct iga1_fifo_depth_select iga1_fifo_depth_select_reg;
+ struct iga2_fifo_depth_select iga2_fifo_depth_select_reg;
+};
+
+struct fifo_threshold_select {
+ struct iga1_fifo_threshold_select iga1_fifo_threshold_select_reg;
+ struct iga2_fifo_threshold_select iga2_fifo_threshold_select_reg;
+};
+
+struct fifo_high_threshold_select {
+ struct iga1_fifo_high_threshold_select
+ iga1_fifo_high_threshold_select_reg;
+ struct iga2_fifo_high_threshold_select
+ iga2_fifo_high_threshold_select_reg;
+};
+
+struct display_queue_expire_num {
+ struct iga1_display_queue_expire_num
+ iga1_display_queue_expire_num_reg;
+ struct iga2_display_queue_expire_num
+ iga2_display_queue_expire_num_reg;
+};
+
+struct iga1_crtc_timing {
+ struct iga1_hor_total hor_total;
+ struct iga1_hor_addr hor_addr;
+ struct iga1_hor_blank_start hor_blank_start;
+ struct iga1_hor_blank_end hor_blank_end;
+ struct iga1_hor_sync_start hor_sync_start;
+ struct iga1_hor_sync_end hor_sync_end;
+ struct iga1_ver_total ver_total;
+ struct iga1_ver_addr ver_addr;
+ struct iga1_ver_blank_start ver_blank_start;
+ struct iga1_ver_blank_end ver_blank_end;
+ struct iga1_ver_sync_start ver_sync_start;
+ struct iga1_ver_sync_end ver_sync_end;
+};
+
+struct iga2_shadow_crtc_timing {
+ struct iga2_shadow_hor_total hor_total_shadow;
+ struct iga2_shadow_hor_blank_end hor_blank_end_shadow;
+ struct iga2_shadow_ver_total ver_total_shadow;
+ struct iga2_shadow_ver_addr ver_addr_shadow;
+ struct iga2_shadow_ver_blank_start ver_blank_start_shadow;
+ struct iga2_shadow_ver_blank_end ver_blank_end_shadow;
+ struct iga2_shadow_ver_sync_start ver_sync_start_shadow;
+ struct iga2_shadow_ver_sync_end ver_sync_end_shadow;
+};
+
+struct iga2_crtc_timing {
+ struct iga2_hor_total hor_total;
+ struct iga2_hor_addr hor_addr;
+ struct iga2_hor_blank_start hor_blank_start;
+ struct iga2_hor_blank_end hor_blank_end;
+ struct iga2_hor_sync_start hor_sync_start;
+ struct iga2_hor_sync_end hor_sync_end;
+ struct iga2_ver_total ver_total;
+ struct iga2_ver_addr ver_addr;
+ struct iga2_ver_blank_start ver_blank_start;
+ struct iga2_ver_blank_end ver_blank_end;
+ struct iga2_ver_sync_start ver_sync_start;
+ struct iga2_ver_sync_end ver_sync_end;
+};
+
+/* device ID */
+#define CLE266 0x3123
+#define KM400 0x3205
+#define CN400_FUNCTION2 0x2259
+#define CN400_FUNCTION3 0x3259
+/* support VT3314 chipset */
+#define CN700_FUNCTION2 0x2314
+#define CN700_FUNCTION3 0x3208
+/* VT3324 chipset */
+#define CX700_FUNCTION2 0x2324
+#define CX700_FUNCTION3 0x3324
+/* VT3204 chipset*/
+#define KM800_FUNCTION3 0x3204
+/* VT3336 chipset*/
+#define KM890_FUNCTION3 0x3336
+/* VT3327 chipset*/
+#define P4M890_FUNCTION3 0x3327
+/* VT3293 chipset*/
+#define CN750_FUNCTION3 0x3208
+/* VT3364 chipset*/
+#define P4M900_FUNCTION3 0x3364
+/* VT3353 chipset*/
+#define VX800_FUNCTION3 0x3353
+
+#define NUM_TOTAL_PLL_TABLE ARRAY_SIZE(pll_value)
+
+struct IODATA {
+ u8 Index;
+ u8 Mask;
+ u8 Data;
+};
+
+struct pci_device_id_info {
+ u32 vendor;
+ u32 device;
+ u32 chip_index;
+};
+
+extern unsigned int viafb_second_virtual_xres;
+extern unsigned int viafb_second_offset;
+extern int viafb_second_size;
+extern int viafb_SAMM_ON;
+extern int viafb_dual_fb;
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+extern int viafb_accel;
+extern int viafb_hotplug;
+
+void viafb_write_reg_mask(u8 index, int io_port, u8 data, u8 mask);
+void viafb_set_output_path(int device, int set_iga,
+ int output_interface);
+void viafb_fill_crtc_timing(struct crt_mode_table *crt_table,
+ int mode_index, int bpp_byte, int set_iga);
+
+void viafb_set_vclock(u32 CLK, int set_iga);
+void viafb_load_reg(int timing_value, int viafb_load_reg_num,
+ struct io_register *reg,
+ int io_type);
+void viafb_crt_disable(void);
+void viafb_crt_enable(void);
+void init_ad9389(void);
+/* Access I/O Function */
+void viafb_write_reg(u8 index, u16 io_port, u8 data);
+u8 viafb_read_reg(int io_port, u8 index);
+void viafb_lock_crt(void);
+void viafb_unlock_crt(void);
+void viafb_load_offset_reg(int h_addr, int bpp_byte, int set_iga);
+void viafb_load_fetch_count_reg(int h_addr, int bpp_byte, int set_iga);
+void viafb_write_regx(struct io_reg RegTable[], int ItemNum);
+struct VideoModeTable *viafb_get_modetbl_pointer(int Index);
+u32 viafb_get_clk_value(int clk);
+void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active);
+void viafb_set_color_depth(int bpp_byte, int set_iga);
+void viafb_set_dpa_gfx(int output_interface, struct GFX_DPA_SETTING\
+ *p_gfx_dpa_setting);
+
+int viafb_setmode(int vmode_index, int hor_res, int ver_res,
+ int video_bpp, int vmode_index1, int hor_res1,
+ int ver_res1, int video_bpp1);
+void viafb_init_chip_info(void);
+void viafb_init_dac(int set_iga);
+int viafb_get_pixclock(int hres, int vres, int vmode_refresh);
+int viafb_get_refresh(int hres, int vres, u32 float_refresh);
+void viafb_update_device_setting(int hres, int vres, int bpp,
+ int vmode_refresh, int flag);
+void viafb_get_mmio_info(unsigned long *mmio_base,
+ unsigned long *mmio_len);
+
+void viafb_set_iga_path(void);
+void viafb_set_start_addr(void);
+void viafb_get_fb_info(unsigned int *fb_base, unsigned int *fb_len);
+
+#endif /* __HW_H__ */
diff --git a/drivers/video/via/iface.c b/drivers/video/via/iface.c
new file mode 100644
index 00000000000..1570636c8d5
--- /dev/null
+++ b/drivers/video/via/iface.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+/* Get frame buffer size from VGA BIOS */
+
+unsigned int viafb_get_memsize(void)
+{
+ unsigned int m;
+
+ /* If memory size provided by user */
+ if (viafb_memsize)
+ m = viafb_memsize * Mb;
+ else {
+ m = (unsigned int)viafb_read_reg(VIASR, SR39);
+ m = m * (4 * Mb);
+
+ if ((m < (16 * Mb)) || (m > (64 * Mb)))
+ m = 16 * Mb;
+ }
+ DEBUG_MSG(KERN_INFO "framebuffer size = %d Mb\n", m / Mb);
+ return m;
+}
+
+/* Get Video Buffer Starting Physical Address(back door)*/
+
+unsigned long viafb_get_videobuf_addr(void)
+{
+ struct pci_dev *pdev = NULL;
+ unsigned char sys_mem;
+ unsigned char video_mem;
+ unsigned long sys_mem_size;
+ unsigned long video_mem_size;
+ /*system memory = 256 MB, video memory 64 MB */
+ unsigned long vmem_starting_adr = 0x0C000000;
+
+ pdev =
+ (struct pci_dev *)pci_get_device(VIA_K800_BRIDGE_VID,
+ VIA_K800_BRIDGE_DID, NULL);
+ if (pdev != NULL) {
+ pci_read_config_byte(pdev, VIA_K800_SYSTEM_MEMORY_REG,
+ &sys_mem);
+ pci_read_config_byte(pdev, VIA_K800_VIDEO_MEMORY_REG,
+ &video_mem);
+ video_mem = (video_mem & 0x70) >> 4;
+ sys_mem_size = ((unsigned long)sys_mem) << 24;
+ if (video_mem != 0)
+ video_mem_size = (1 << (video_mem)) * 1024 * 1024;
+ else
+ video_mem_size = 0;
+
+ vmem_starting_adr = sys_mem_size - video_mem_size;
+ pci_dev_put(pdev);
+ }
+
+ DEBUG_MSG(KERN_INFO "Video Memory Starting Address = %lx \n",
+ vmem_starting_adr);
+ return vmem_starting_adr;
+}
diff --git a/drivers/video/via/iface.h b/drivers/video/via/iface.h
new file mode 100644
index 00000000000..790ec3e3aea
--- /dev/null
+++ b/drivers/video/via/iface.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __IFACE_H__
+#define __IFACE_H__
+
+#define Kb (1024)
+#define Mb (Kb*Kb)
+
+#define VIA_K800_BRIDGE_VID 0x1106
+#define VIA_K800_BRIDGE_DID 0x3204
+
+#define VIA_K800_SYSTEM_MEMORY_REG 0x47
+#define VIA_K800_VIDEO_MEMORY_REG 0xA1
+
+extern int viafb_memsize;
+unsigned int viafb_get_memsize(void);
+unsigned long viafb_get_videobuf_addr(void);
+
+#endif /* __IFACE_H__ */
diff --git a/drivers/video/via/ioctl.c b/drivers/video/via/ioctl.c
new file mode 100644
index 00000000000..da03c074e32
--- /dev/null
+++ b/drivers/video/via/ioctl.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+int viafb_ioctl_get_viafb_info(u_long arg)
+{
+ struct viafb_ioctl_info viainfo;
+
+ viainfo.viafb_id = VIAID;
+ viainfo.vendor_id = PCI_VIA_VENDOR_ID;
+
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ viainfo.device_id = UNICHROME_CLE266_DID;
+ break;
+
+ case UNICHROME_K400:
+ viainfo.device_id = UNICHROME_K400_DID;
+ break;
+
+ case UNICHROME_K800:
+ viainfo.device_id = UNICHROME_K800_DID;
+ break;
+
+ case UNICHROME_PM800:
+ viainfo.device_id = UNICHROME_PM800_DID;
+ break;
+
+ case UNICHROME_CN700:
+ viainfo.device_id = UNICHROME_CN700_DID;
+ break;
+
+ case UNICHROME_CX700:
+ viainfo.device_id = UNICHROME_CX700_DID;
+ break;
+
+ case UNICHROME_K8M890:
+ viainfo.device_id = UNICHROME_K8M890_DID;
+ break;
+
+ case UNICHROME_P4M890:
+ viainfo.device_id = UNICHROME_P4M890_DID;
+ break;
+
+ case UNICHROME_P4M900:
+ viainfo.device_id = UNICHROME_P4M900_DID;
+ break;
+ }
+
+ viainfo.version = VERSION_MAJOR;
+ viainfo.revision = VERSION_MINOR;
+
+ if (copy_to_user((void __user *)arg, &viainfo, sizeof(viainfo)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/* Hot-Plug Priority: DVI > CRT*/
+int viafb_ioctl_hotplug(int hres, int vres, int bpp)
+{
+ int DVIsense, status = 0;
+ DEBUG_MSG(KERN_INFO "viafb_ioctl_hotplug!!\n");
+
+ if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name !=
+ NON_TMDS_TRANSMITTER) {
+ DVIsense = viafb_dvi_sense();
+
+ if (DVIsense) {
+ DEBUG_MSG(KERN_INFO "DVI Attached...\n");
+ if (viafb_DeviceStatus != DVI_Device) {
+ viafb_DVI_ON = 1;
+ viafb_CRT_ON = 0;
+ viafb_LCD_ON = 0;
+ viafb_DeviceStatus = DVI_Device;
+ return viafb_DeviceStatus;
+ }
+ status = 1;
+ } else
+ DEBUG_MSG(KERN_INFO "DVI De-attached...\n");
+ }
+
+ if ((viafb_DeviceStatus != CRT_Device) && (status == 0)) {
+ viafb_CRT_ON = 1;
+ viafb_DVI_ON = 0;
+ viafb_LCD_ON = 0;
+
+ viafb_DeviceStatus = CRT_Device;
+ return viafb_DeviceStatus;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/via/ioctl.h b/drivers/video/via/ioctl.h
new file mode 100644
index 00000000000..842fe30b986
--- /dev/null
+++ b/drivers/video/via/ioctl.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __IOCTL_H__
+#define __IOCTL_H__
+
+#ifndef __user
+#define __user
+#endif
+
+/* VIAFB IOCTL definition */
+#define VIAFB_GET_INFO_SIZE 0x56494101 /* 'VIA\01' */
+#define VIAFB_GET_INFO 0x56494102 /* 'VIA\02' */
+#define VIAFB_HOTPLUG 0x56494103 /* 'VIA\03' */
+#define VIAFB_SET_HOTPLUG_FLAG 0x56494104 /* 'VIA\04' */
+#define VIAFB_GET_RESOLUTION 0x56494105 /* 'VIA\05' */
+#define VIAFB_GET_SAMM_INFO 0x56494107 /* 'VIA\07' */
+#define VIAFB_TURN_ON_OUTPUT_DEVICE 0x56494108 /* 'VIA\08' */
+#define VIAFB_TURN_OFF_OUTPUT_DEVICE 0x56494109 /* 'VIA\09' */
+#define VIAFB_SET_DEVICE 0x5649410A
+#define VIAFB_GET_DEVICE 0x5649410B
+#define VIAFB_GET_DRIVER_VERSION 0x56494112 /* 'VIA\12' */
+#define VIAFB_GET_CHIP_INFO 0x56494113 /* 'VIA\13' */
+#define VIAFB_SET_DEVICE_INFO 0x56494114
+#define VIAFB_GET_DEVICE_INFO 0x56494115
+
+#define VIAFB_GET_DEVICE_SUPPORT 0x56494118
+#define VIAFB_GET_DEVICE_CONNECT 0x56494119
+#define VIAFB_GET_PANEL_SUPPORT_EXPAND 0x5649411A
+#define VIAFB_GET_DRIVER_NAME 0x56494122
+#define VIAFB_GET_DEVICE_SUPPORT_STATE 0x56494123
+#define VIAFB_GET_GAMMA_LUT 0x56494124
+#define VIAFB_SET_GAMMA_LUT 0x56494125
+#define VIAFB_GET_GAMMA_SUPPORT_STATE 0x56494126
+#define VIAFB_SET_VIDEO_DEVICE 0x56494127
+#define VIAFB_GET_VIDEO_DEVICE 0x56494128
+#define VIAFB_SET_SECOND_MODE 0x56494129
+#define VIAFB_SYNC_SURFACE 0x56494130
+#define VIAFB_GET_DRIVER_CAPS 0x56494131
+#define VIAFB_GET_IGA_SCALING_INFO 0x56494132
+#define VIAFB_GET_PANEL_MAX_SIZE 0x56494133
+#define VIAFB_GET_PANEL_MAX_POSITION 0x56494134
+#define VIAFB_SET_PANEL_SIZE 0x56494135
+#define VIAFB_SET_PANEL_POSITION 0x56494136
+#define VIAFB_GET_PANEL_POSITION 0x56494137
+#define VIAFB_GET_PANEL_SIZE 0x56494138
+
+#define None_Device 0x00
+#define CRT_Device 0x01
+#define LCD_Device 0x02
+#define DVI_Device 0x08
+#define CRT2_Device 0x10
+#define LCD2_Device 0x40
+
+#define OP_LCD_CENTERING 0x01
+#define OP_LCD_PANEL_ID 0x02
+#define OP_LCD_MODE 0x03
+
+/*SAMM operation flag*/
+#define OP_SAMM 0x80
+
+#define LCD_PANEL_ID_MAXIMUM 22
+
+#define STATE_ON 0x1
+#define STATE_OFF 0x0
+#define STATE_DEFAULT 0xFFFF
+
+#define MAX_ACTIVE_DEV_NUM 2
+
+struct device_t {
+ unsigned short crt:1;
+ unsigned short dvi:1;
+ unsigned short lcd:1;
+ unsigned short samm:1;
+ unsigned short lcd_dsp_cent:1;
+ unsigned char lcd_mode:1;
+ unsigned short epia_dvi:1;
+ unsigned short lcd_dual_edge:1;
+ unsigned short lcd2:1;
+
+ unsigned short primary_dev;
+ unsigned char lcd_panel_id;
+ unsigned short xres, yres;
+ unsigned short xres1, yres1;
+ unsigned short refresh;
+ unsigned short bpp;
+ unsigned short refresh1;
+ unsigned short bpp1;
+ unsigned short sequence;
+ unsigned short bus_width;
+};
+
+struct viafb_ioctl_info {
+ u32 viafb_id; /* for identifying viafb */
+#define VIAID 0x56494146 /* Identify myself with 'VIAF' */
+ u16 vendor_id;
+ u16 device_id;
+ u8 version;
+ u8 revision;
+ u8 reserved[246]; /* for future use */
+};
+
+struct viafb_ioctl_mode {
+ u32 xres;
+ u32 yres;
+ u32 refresh;
+ u32 bpp;
+ u32 xres_sec;
+ u32 yres_sec;
+ u32 virtual_xres_sec;
+ u32 virtual_yres_sec;
+ u32 refresh_sec;
+ u32 bpp_sec;
+};
+struct viafb_ioctl_samm {
+ u32 samm_status;
+ u32 size_prim;
+ u32 size_sec;
+ u32 mem_base;
+ u32 offset_sec;
+};
+
+struct viafb_driver_version {
+ int iMajorNum;
+ int iKernelNum;
+ int iOSNum;
+ int iMinorNum;
+};
+
+struct viafb_ioctl_lcd_attribute {
+ unsigned int panel_id;
+ unsigned int display_center;
+ unsigned int lcd_mode;
+};
+
+struct viafb_ioctl_setting {
+ /* Enable or disable active devices */
+ unsigned short device_flag;
+ /* Indicate which device should be turn on or turn off. */
+ unsigned short device_status;
+ unsigned int reserved;
+ /* Indicate which LCD's attribute can be changed. */
+ unsigned short lcd_operation_flag;
+ /* 1: SAMM ON 0: SAMM OFF */
+ unsigned short samm_status;
+ /* horizontal resolution of first device */
+ unsigned short first_dev_hor_res;
+ /* vertical resolution of first device */
+ unsigned short first_dev_ver_res;
+ /* horizontal resolution of second device */
+ unsigned short second_dev_hor_res;
+ /* vertical resolution of second device */
+ unsigned short second_dev_ver_res;
+ /* refresh rate of first device */
+ unsigned short first_dev_refresh;
+ /* bpp of first device */
+ unsigned short first_dev_bpp;
+ /* refresh rate of second device */
+ unsigned short second_dev_refresh;
+ /* bpp of second device */
+ unsigned short second_dev_bpp;
+ /* Indicate which device are primary display device. */
+ unsigned int primary_device;
+ /* Indicate which device will show video. only valid in duoview mode */
+ unsigned int video_device_status;
+ unsigned int struct_reserved[34];
+ struct viafb_ioctl_lcd_attribute lcd_attributes;
+};
+
+struct _UTFunctionCaps {
+ unsigned int dw3DScalingState;
+ unsigned int reserved[31];
+};
+
+struct _POSITIONVALUE {
+ unsigned int dwX;
+ unsigned int dwY;
+};
+
+struct _panel_size_pos_info {
+ unsigned int device_type;
+ int x;
+ int y;
+};
+
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+
+int viafb_ioctl_get_viafb_info(u_long arg);
+int viafb_ioctl_hotplug(int hres, int vres, int bpp);
+
+#endif /* __IOCTL_H__ */
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
new file mode 100644
index 00000000000..6c7290a6a44
--- /dev/null
+++ b/drivers/video/via/lcd.c
@@ -0,0 +1,1821 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+#include "lcdtbl.h"
+
+static struct iga2_shadow_crtc_timing iga2_shadow_crtc_reg = {
+ /* IGA2 Shadow Horizontal Total */
+ {IGA2_SHADOW_HOR_TOTAL_REG_NUM, {{CR6D, 0, 7}, {CR71, 3, 3} } },
+ /* IGA2 Shadow Horizontal Blank End */
+ {IGA2_SHADOW_HOR_BLANK_END_REG_NUM, {{CR6E, 0, 7} } },
+ /* IGA2 Shadow Vertical Total */
+ {IGA2_SHADOW_VER_TOTAL_REG_NUM, {{CR6F, 0, 7}, {CR71, 0, 2} } },
+ /* IGA2 Shadow Vertical Addressable Video */
+ {IGA2_SHADOW_VER_ADDR_REG_NUM, {{CR70, 0, 7}, {CR71, 4, 6} } },
+ /* IGA2 Shadow Vertical Blank Start */
+ {IGA2_SHADOW_VER_BLANK_START_REG_NUM,
+ {{CR72, 0, 7}, {CR74, 4, 6} } },
+ /* IGA2 Shadow Vertical Blank End */
+ {IGA2_SHADOW_VER_BLANK_END_REG_NUM, {{CR73, 0, 7}, {CR74, 0, 2} } },
+ /* IGA2 Shadow Vertical Sync Start */
+ {IGA2_SHADOW_VER_SYNC_START_REG_NUM, {{CR75, 0, 7}, {CR76, 4, 6} } },
+ /* IGA2 Shadow Vertical Sync End */
+ {IGA2_SHADOW_VER_SYNC_END_REG_NUM, {{CR76, 0, 3} } }
+};
+
+static struct _lcd_scaling_factor lcd_scaling_factor = {
+ /* LCD Horizontal Scaling Factor Register */
+ {LCD_HOR_SCALING_FACTOR_REG_NUM,
+ {{CR9F, 0, 1}, {CR77, 0, 7}, {CR79, 4, 5} } },
+ /* LCD Vertical Scaling Factor Register */
+ {LCD_VER_SCALING_FACTOR_REG_NUM,
+ {{CR79, 3, 3}, {CR78, 0, 7}, {CR79, 6, 7} } }
+};
+static struct _lcd_scaling_factor lcd_scaling_factor_CLE = {
+ /* LCD Horizontal Scaling Factor Register */
+ {LCD_HOR_SCALING_FACTOR_REG_NUM_CLE, {{CR77, 0, 7}, {CR79, 4, 5} } },
+ /* LCD Vertical Scaling Factor Register */
+ {LCD_VER_SCALING_FACTOR_REG_NUM_CLE, {{CR78, 0, 7}, {CR79, 6, 7} } }
+};
+
+static int check_lvds_chip(int device_id_subaddr, int device_id);
+static bool lvds_identify_integratedlvds(void);
+static int fp_id_to_vindex(int panel_id);
+static int lvds_register_read(int index);
+static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
+ int panel_vres);
+static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
+ int panel_id);
+static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
+ int panel_id);
+static void load_lcd_patch_regs(int set_hres, int set_vres,
+ int panel_id, int set_iga);
+static void via_pitch_alignment_patch_lcd(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information
+ *plvds_chip_info);
+static void lcd_patch_skew_dvp0(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+static void lcd_patch_skew_dvp1(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+static void lcd_patch_skew(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
+
+static void integrated_lvds_disable(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+static void integrated_lvds_enable(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+static void lcd_powersequence_off(void);
+static void lcd_powersequence_on(void);
+static void fill_lcd_format(void);
+static void check_diport_of_integrated_lvds(
+ struct lvds_chip_information *plvds_chip_info,
+ struct lvds_setting_information
+ *plvds_setting_info);
+static struct display_timing lcd_centering_timging(struct display_timing
+ mode_crt_reg,
+ struct display_timing panel_crt_reg);
+static void load_crtc_shadow_timing(struct display_timing mode_timing,
+ struct display_timing panel_timing);
+static void viafb_load_scaling_factor_for_p4m900(int set_hres,
+ int set_vres, int panel_hres, int panel_vres);
+
+static int check_lvds_chip(int device_id_subaddr, int device_id)
+{
+ if (lvds_register_read(device_id_subaddr) == device_id)
+ return OK;
+ else
+ return FAIL;
+}
+
+void viafb_init_lcd_size(void)
+{
+ DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
+ DEBUG_MSG(KERN_INFO
+ "viaparinfo->lvds_setting_info->get_lcd_size_method %d\n",
+ viaparinfo->lvds_setting_info->get_lcd_size_method);
+
+ switch (viaparinfo->lvds_setting_info->get_lcd_size_method) {
+ case GET_LCD_SIZE_BY_SYSTEM_BIOS:
+ break;
+ case GET_LCD_SZIE_BY_HW_STRAPPING:
+ break;
+ case GET_LCD_SIZE_BY_VGA_BIOS:
+ DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n");
+ viaparinfo->lvds_setting_info->lcd_panel_size =
+ fp_id_to_vindex(viafb_lcd_panel_id);
+ DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
+ viaparinfo->lvds_setting_info->lcd_panel_id);
+ DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
+ viaparinfo->lvds_setting_info->lcd_panel_size);
+ break;
+ case GET_LCD_SIZE_BY_USER_SETTING:
+ DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n");
+ viaparinfo->lvds_setting_info->lcd_panel_size =
+ fp_id_to_vindex(viafb_lcd_panel_id);
+ DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
+ viaparinfo->lvds_setting_info->lcd_panel_id);
+ DEBUG_MSG(KERN_INFO "LCD Panel Size = %d\n",
+ viaparinfo->lvds_setting_info->lcd_panel_size);
+ break;
+ default:
+ DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n");
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID1_800X600;
+ viaparinfo->lvds_setting_info->lcd_panel_size =
+ fp_id_to_vindex(LCD_PANEL_ID1_800X600);
+ }
+ viaparinfo->lvds_setting_info2->lcd_panel_id =
+ viaparinfo->lvds_setting_info->lcd_panel_id;
+ viaparinfo->lvds_setting_info2->lcd_panel_size =
+ viaparinfo->lvds_setting_info->lcd_panel_size;
+ viaparinfo->lvds_setting_info2->lcd_panel_hres =
+ viaparinfo->lvds_setting_info->lcd_panel_hres;
+ viaparinfo->lvds_setting_info2->lcd_panel_vres =
+ viaparinfo->lvds_setting_info->lcd_panel_vres;
+ viaparinfo->lvds_setting_info2->device_lcd_dualedge =
+ viaparinfo->lvds_setting_info->device_lcd_dualedge;
+ viaparinfo->lvds_setting_info2->LCDDithering =
+ viaparinfo->lvds_setting_info->LCDDithering;
+}
+
+static bool lvds_identify_integratedlvds(void)
+{
+ if (viafb_display_hardware_layout == HW_LAYOUT_LCD_EXTERNAL_LCD2) {
+ /* Two dual channel LCD (Internal LVDS + External LVDS): */
+ /* If we have an external LVDS, such as VT1636, we should
+ have its chip ID already. */
+ if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
+ INTEGRATED_LVDS;
+ DEBUG_MSG(KERN_INFO "Support two dual channel LVDS!\
+ (Internal LVDS + External LVDS)\n");
+ } else {
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ INTEGRATED_LVDS;
+ DEBUG_MSG(KERN_INFO "Not found external LVDS,\
+ so can't support two dual channel LVDS!\n");
+ }
+ } else if (viafb_display_hardware_layout == HW_LAYOUT_LCD1_LCD2) {
+ /* Two single channel LCD (Internal LVDS + Internal LVDS): */
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ INTEGRATED_LVDS;
+ viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name =
+ INTEGRATED_LVDS;
+ DEBUG_MSG(KERN_INFO "Support two single channel LVDS!\
+ (Internal LVDS + Internal LVDS)\n");
+ } else if (viafb_display_hardware_layout != HW_LAYOUT_DVI_ONLY) {
+ /* If we have found external LVDS, just use it,
+ otherwise, we will use internal LVDS as default. */
+ if (!viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ INTEGRATED_LVDS;
+ DEBUG_MSG(KERN_INFO "Found Integrated LVDS!\n");
+ }
+ } else {
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ NON_LVDS_TRANSMITTER;
+ DEBUG_MSG(KERN_INFO "Do not support LVDS!\n");
+ return false;
+ }
+
+ return true;
+}
+
+int viafb_lvds_trasmitter_identify(void)
+{
+ viaparinfo->i2c_stuff.i2c_port = I2CPORTINDEX;
+ if (viafb_lvds_identify_vt1636()) {
+ viaparinfo->chip_info->lvds_chip_info.i2c_port = I2CPORTINDEX;
+ DEBUG_MSG(KERN_INFO
+ "Found VIA VT1636 LVDS on port i2c 0x31 \n");
+ } else {
+ viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX;
+ if (viafb_lvds_identify_vt1636()) {
+ viaparinfo->chip_info->lvds_chip_info.i2c_port =
+ GPIOPORTINDEX;
+ DEBUG_MSG(KERN_INFO
+ "Found VIA VT1636 LVDS on port gpio 0x2c \n");
+ }
+ }
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700)
+ lvds_identify_integratedlvds();
+
+ if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+ return true;
+ /* Check for VT1631: */
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name = VT1631_LVDS;
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+ VT1631_LVDS_I2C_ADDR;
+
+ if (check_lvds_chip(VT1631_DEVICE_ID_REG, VT1631_DEVICE_ID) != FAIL) {
+ DEBUG_MSG(KERN_INFO "\n VT1631 LVDS ! \n");
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+ DEBUG_MSG(KERN_INFO "\n %2d",
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name);
+ return OK;
+ }
+
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ NON_LVDS_TRANSMITTER;
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+ VT1631_LVDS_I2C_ADDR;
+ return FAIL;
+}
+
+static int fp_id_to_vindex(int panel_id)
+{
+ DEBUG_MSG(KERN_INFO "fp_get_panel_id()\n");
+
+ if (panel_id > LCD_PANEL_ID_MAXIMUM)
+ viafb_lcd_panel_id = panel_id =
+ viafb_read_reg(VIACR, CR3F) & 0x0F;
+
+ switch (panel_id) {
+ case 0x0:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 640;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID0_640X480;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_640X480;
+ break;
+ case 0x1:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID1_800X600;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_800X600;
+ break;
+ case 0x2:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID2_1024X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1024X768;
+ break;
+ case 0x3:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID3_1280X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1280X768;
+ break;
+ case 0x4:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID4_1280X1024;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1280X1024;
+ break;
+ case 0x5:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID5_1400X1050;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1400X1050;
+ break;
+ case 0x6:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID6_1600X1200;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1600X1200;
+ break;
+ case 0x8:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 480;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_IDA_800X480;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_800X480;
+ break;
+ case 0x9:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID2_1024X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1024X768;
+ break;
+ case 0xA:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID2_1024X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1024X768;
+ break;
+ case 0xB:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID2_1024X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1024X768;
+ break;
+ case 0xC:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID3_1280X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1280X768;
+ break;
+ case 0xD:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID4_1280X1024;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1280X1024;
+ break;
+ case 0xE:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1400;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1050;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID5_1400X1050;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1400X1050;
+ break;
+ case 0xF:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1600;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 1200;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID6_1600X1200;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1600X1200;
+ break;
+ case 0x10:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1366;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID7_1366X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1368X768;
+ break;
+ case 0x11:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1024;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID8_1024X600;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1024X600;
+ break;
+ case 0x12:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID3_1280X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1280X768;
+ break;
+ case 0x13:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 800;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID9_1280X800;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_1280X800;
+ break;
+ case 0x14:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1360;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_IDB_1360X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1360X768;
+ break;
+ case 0x15:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 1280;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 768;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID3_1280X768;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 1;
+ viaparinfo->lvds_setting_info->LCDDithering = 0;
+ return VIA_RES_1280X768;
+ break;
+ case 0x16:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 480;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 640;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_IDC_480X640;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_480X640;
+ break;
+ default:
+ viaparinfo->lvds_setting_info->lcd_panel_hres = 800;
+ viaparinfo->lvds_setting_info->lcd_panel_vres = 600;
+ viaparinfo->lvds_setting_info->lcd_panel_id =
+ LCD_PANEL_ID1_800X600;
+ viaparinfo->lvds_setting_info->device_lcd_dualedge = 0;
+ viaparinfo->lvds_setting_info->LCDDithering = 1;
+ return VIA_RES_800X600;
+ }
+}
+
+static int lvds_register_read(int index)
+{
+ u8 data;
+
+ viaparinfo->i2c_stuff.i2c_port = GPIOPORTINDEX;
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->
+ lvds_chip_info.lvds_chip_slave_addr,
+ (u8) index, &data);
+ return data;
+}
+
+static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
+ int panel_vres)
+{
+ int reg_value = 0;
+ int viafb_load_reg_num;
+ struct io_register *reg = NULL;
+
+ DEBUG_MSG(KERN_INFO "load_lcd_scaling()!!\n");
+
+ /* LCD Scaling Enable */
+ viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
+ if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
+ viafb_load_scaling_factor_for_p4m900(set_hres, set_vres,
+ panel_hres, panel_vres);
+ return;
+ }
+
+ /* Check if expansion for horizontal */
+ if (set_hres != panel_hres) {
+ /* Load Horizontal Scaling Factor */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ reg_value =
+ CLE266_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+ viafb_load_reg_num =
+ lcd_scaling_factor_CLE.lcd_hor_scaling_factor.
+ reg_num;
+ reg = lcd_scaling_factor_CLE.lcd_hor_scaling_factor.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ break;
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ reg_value =
+ K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+ /* Horizontal scaling enabled */
+ viafb_write_reg_mask(CRA2, VIACR, 0xC0, BIT7 + BIT6);
+ viafb_load_reg_num =
+ lcd_scaling_factor.lcd_hor_scaling_factor.reg_num;
+ reg = lcd_scaling_factor.lcd_hor_scaling_factor.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ break;
+ }
+
+ DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d", reg_value);
+ } else {
+ /* Horizontal scaling disabled */
+ viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT7);
+ }
+
+ /* Check if expansion for vertical */
+ if (set_vres != panel_vres) {
+ /* Load Vertical Scaling Factor */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ reg_value =
+ CLE266_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+ viafb_load_reg_num =
+ lcd_scaling_factor_CLE.lcd_ver_scaling_factor.
+ reg_num;
+ reg = lcd_scaling_factor_CLE.lcd_ver_scaling_factor.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ break;
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ reg_value =
+ K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+ /* Vertical scaling enabled */
+ viafb_write_reg_mask(CRA2, VIACR, 0x08, BIT3);
+ viafb_load_reg_num =
+ lcd_scaling_factor.lcd_ver_scaling_factor.reg_num;
+ reg = lcd_scaling_factor.lcd_ver_scaling_factor.reg;
+ viafb_load_reg(reg_value,
+ viafb_load_reg_num, reg, VIACR);
+ break;
+ }
+
+ DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d", reg_value);
+ } else {
+ /* Vertical scaling disabled */
+ viafb_write_reg_mask(CRA2, VIACR, 0x00, BIT3);
+ }
+}
+
+static void load_lcd_k400_patch_tbl(int set_hres, int set_vres,
+ int panel_id)
+{
+ int vmode_index;
+ int reg_num = 0;
+ struct io_reg *lcd_patch_reg = NULL;
+
+ if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+ else
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+ switch (panel_id) {
+ /* LCD 800x600 */
+ case LCD_PANEL_ID1_800X600:
+ switch (vmode_index) {
+ case VIA_RES_640X400:
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_8X6;
+ lcd_patch_reg = K400_LCD_RES_6X4_8X6;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_K400_LCD_RES_7X4_8X6;
+ lcd_patch_reg = K400_LCD_RES_7X4_8X6;
+ break;
+ }
+ break;
+
+ /* LCD 1024x768 */
+ case LCD_PANEL_ID2_1024X768:
+ switch (vmode_index) {
+ case VIA_RES_640X400:
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_10X7;
+ lcd_patch_reg = K400_LCD_RES_6X4_10X7;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_K400_LCD_RES_7X4_10X7;
+ lcd_patch_reg = K400_LCD_RES_7X4_10X7;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_K400_LCD_RES_8X6_10X7;
+ lcd_patch_reg = K400_LCD_RES_8X6_10X7;
+ break;
+ }
+ break;
+
+ /* LCD 1280x1024 */
+ case LCD_PANEL_ID4_1280X1024:
+ switch (vmode_index) {
+ case VIA_RES_640X400:
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_12X10;
+ lcd_patch_reg = K400_LCD_RES_6X4_12X10;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_K400_LCD_RES_7X4_12X10;
+ lcd_patch_reg = K400_LCD_RES_7X4_12X10;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_K400_LCD_RES_8X6_12X10;
+ lcd_patch_reg = K400_LCD_RES_8X6_12X10;
+ break;
+ case VIA_RES_1024X768:
+ reg_num = NUM_TOTAL_K400_LCD_RES_10X7_12X10;
+ lcd_patch_reg = K400_LCD_RES_10X7_12X10;
+ break;
+
+ }
+ break;
+
+ /* LCD 1400x1050 */
+ case LCD_PANEL_ID5_1400X1050:
+ switch (vmode_index) {
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_14X10;
+ lcd_patch_reg = K400_LCD_RES_6X4_14X10;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_K400_LCD_RES_8X6_14X10;
+ lcd_patch_reg = K400_LCD_RES_8X6_14X10;
+ break;
+ case VIA_RES_1024X768:
+ reg_num = NUM_TOTAL_K400_LCD_RES_10X7_14X10;
+ lcd_patch_reg = K400_LCD_RES_10X7_14X10;
+ break;
+ case VIA_RES_1280X768:
+ case VIA_RES_1280X800:
+ case VIA_RES_1280X960:
+ case VIA_RES_1280X1024:
+ reg_num = NUM_TOTAL_K400_LCD_RES_12X10_14X10;
+ lcd_patch_reg = K400_LCD_RES_12X10_14X10;
+ break;
+ }
+ break;
+
+ /* LCD 1600x1200 */
+ case LCD_PANEL_ID6_1600X1200:
+ switch (vmode_index) {
+ case VIA_RES_640X400:
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_16X12;
+ lcd_patch_reg = K400_LCD_RES_6X4_16X12;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_K400_LCD_RES_7X4_16X12;
+ lcd_patch_reg = K400_LCD_RES_7X4_16X12;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_K400_LCD_RES_8X6_16X12;
+ lcd_patch_reg = K400_LCD_RES_8X6_16X12;
+ break;
+ case VIA_RES_1024X768:
+ reg_num = NUM_TOTAL_K400_LCD_RES_10X7_16X12;
+ lcd_patch_reg = K400_LCD_RES_10X7_16X12;
+ break;
+ case VIA_RES_1280X768:
+ case VIA_RES_1280X800:
+ case VIA_RES_1280X960:
+ case VIA_RES_1280X1024:
+ reg_num = NUM_TOTAL_K400_LCD_RES_12X10_16X12;
+ lcd_patch_reg = K400_LCD_RES_12X10_16X12;
+ break;
+ }
+ break;
+
+ /* LCD 1366x768 */
+ case LCD_PANEL_ID7_1366X768:
+ switch (vmode_index) {
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_K400_LCD_RES_6X4_1366X7;
+ lcd_patch_reg = K400_LCD_RES_6X4_1366X7;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_K400_LCD_RES_7X4_1366X7;
+ lcd_patch_reg = K400_LCD_RES_7X4_1366X7;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_K400_LCD_RES_8X6_1366X7;
+ lcd_patch_reg = K400_LCD_RES_8X6_1366X7;
+ break;
+ case VIA_RES_1024X768:
+ reg_num = NUM_TOTAL_K400_LCD_RES_10X7_1366X7;
+ lcd_patch_reg = K400_LCD_RES_10X7_1366X7;
+ break;
+ case VIA_RES_1280X768:
+ case VIA_RES_1280X800:
+ case VIA_RES_1280X960:
+ case VIA_RES_1280X1024:
+ reg_num = NUM_TOTAL_K400_LCD_RES_12X10_1366X7;
+ lcd_patch_reg = K400_LCD_RES_12X10_1366X7;
+ break;
+ }
+ break;
+
+ /* LCD 1360x768 */
+ case LCD_PANEL_IDB_1360X768:
+ break;
+ }
+ if (reg_num != 0) {
+ /* H.W. Reset : ON */
+ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+ viafb_write_regx(lcd_patch_reg, reg_num);
+
+ /* H.W. Reset : OFF */
+ viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+ /* Reset PLL */
+ viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+ viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+
+ /* Fire! */
+ outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
+ }
+}
+
+static void load_lcd_p880_patch_tbl(int set_hres, int set_vres,
+ int panel_id)
+{
+ int vmode_index;
+ int reg_num = 0;
+ struct io_reg *lcd_patch_reg = NULL;
+
+ if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+ else
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+
+ switch (panel_id) {
+ case LCD_PANEL_ID5_1400X1050:
+ switch (vmode_index) {
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_P880_LCD_RES_6X4_14X10;
+ lcd_patch_reg = P880_LCD_RES_6X4_14X10;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_P880_LCD_RES_8X6_14X10;
+ lcd_patch_reg = P880_LCD_RES_8X6_14X10;
+ break;
+ }
+ break;
+ case LCD_PANEL_ID6_1600X1200:
+ switch (vmode_index) {
+ case VIA_RES_640X400:
+ case VIA_RES_640X480:
+ reg_num = NUM_TOTAL_P880_LCD_RES_6X4_16X12;
+ lcd_patch_reg = P880_LCD_RES_6X4_16X12;
+ break;
+ case VIA_RES_720X480:
+ case VIA_RES_720X576:
+ reg_num = NUM_TOTAL_P880_LCD_RES_7X4_16X12;
+ lcd_patch_reg = P880_LCD_RES_7X4_16X12;
+ break;
+ case VIA_RES_800X600:
+ reg_num = NUM_TOTAL_P880_LCD_RES_8X6_16X12;
+ lcd_patch_reg = P880_LCD_RES_8X6_16X12;
+ break;
+ case VIA_RES_1024X768:
+ reg_num = NUM_TOTAL_P880_LCD_RES_10X7_16X12;
+ lcd_patch_reg = P880_LCD_RES_10X7_16X12;
+ break;
+ case VIA_RES_1280X768:
+ case VIA_RES_1280X960:
+ case VIA_RES_1280X1024:
+ reg_num = NUM_TOTAL_P880_LCD_RES_12X10_16X12;
+ lcd_patch_reg = P880_LCD_RES_12X10_16X12;
+ break;
+ }
+ break;
+
+ }
+ if (reg_num != 0) {
+ /* H.W. Reset : ON */
+ viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
+
+ viafb_write_regx(lcd_patch_reg, reg_num);
+
+ /* H.W. Reset : OFF */
+ viafb_write_reg_mask(CR17, VIACR, 0x80, BIT7);
+
+ /* Reset PLL */
+ viafb_write_reg_mask(SR40, VIASR, 0x02, BIT1);
+ viafb_write_reg_mask(SR40, VIASR, 0x00, BIT1);
+
+ /* Fire! */
+ outb(inb(VIARMisc) | (BIT2 + BIT3), VIAWMisc);
+ }
+}
+
+static void load_lcd_patch_regs(int set_hres, int set_vres,
+ int panel_id, int set_iga)
+{
+ int vmode_index;
+
+ if (viaparinfo->lvds_setting_info->iga_path == IGA2)
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 1);
+ else
+ vmode_index = viafb_get_mode_index(set_hres, set_vres, 0);
+
+ viafb_unlock_crt();
+
+ /* Patch for simultaneous & Expansion */
+ if ((set_iga == IGA1_IGA2) &&
+ (viaparinfo->lvds_setting_info->display_method ==
+ LCD_EXPANDSION)) {
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ load_lcd_k400_patch_tbl(set_hres, set_vres, panel_id);
+ break;
+ case UNICHROME_K800:
+ break;
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ load_lcd_p880_patch_tbl(set_hres, set_vres, panel_id);
+ }
+ }
+
+ viafb_lock_crt();
+}
+
+static void via_pitch_alignment_patch_lcd(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information
+ *plvds_chip_info)
+{
+ unsigned char cr13, cr35, cr65, cr66, cr67;
+ unsigned long dwScreenPitch = 0;
+ unsigned long dwPitch;
+
+ dwPitch = plvds_setting_info->h_active * (plvds_setting_info->bpp >> 3);
+ if (dwPitch & 0x1F) {
+ dwScreenPitch = ((dwPitch + 31) & ~31) >> 3;
+ if (plvds_setting_info->iga_path == IGA2) {
+ if (plvds_setting_info->bpp > 8) {
+ cr66 = (unsigned char)(dwScreenPitch & 0xFF);
+ viafb_write_reg(CR66, VIACR, cr66);
+ cr67 = viafb_read_reg(VIACR, CR67) & 0xFC;
+ cr67 |=
+ (unsigned
+ char)((dwScreenPitch & 0x300) >> 8);
+ viafb_write_reg(CR67, VIACR, cr67);
+ }
+
+ /* Fetch Count */
+ cr67 = viafb_read_reg(VIACR, CR67) & 0xF3;
+ cr67 |= (unsigned char)((dwScreenPitch & 0x600) >> 7);
+ viafb_write_reg(CR67, VIACR, cr67);
+ cr65 = (unsigned char)((dwScreenPitch >> 1) & 0xFF);
+ cr65 += 2;
+ viafb_write_reg(CR65, VIACR, cr65);
+ } else {
+ if (plvds_setting_info->bpp > 8) {
+ cr13 = (unsigned char)(dwScreenPitch & 0xFF);
+ viafb_write_reg(CR13, VIACR, cr13);
+ cr35 = viafb_read_reg(VIACR, CR35) & 0x1F;
+ cr35 |=
+ (unsigned
+ char)((dwScreenPitch & 0x700) >> 3);
+ viafb_write_reg(CR35, VIACR, cr35);
+ }
+ }
+ }
+}
+static void lcd_patch_skew_dvp0(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_P4M900:
+ viafb_vt1636_patch_skew_on_vt3364(plvds_setting_info,
+ plvds_chip_info);
+ break;
+ case UNICHROME_P4M890:
+ viafb_vt1636_patch_skew_on_vt3327(plvds_setting_info,
+ plvds_chip_info);
+ break;
+ }
+ }
+}
+static void lcd_patch_skew_dvp1(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ if (VT1636_LVDS == plvds_chip_info->lvds_chip_name) {
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CX700:
+ viafb_vt1636_patch_skew_on_vt3324(plvds_setting_info,
+ plvds_chip_info);
+ break;
+ }
+ }
+}
+static void lcd_patch_skew(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
+{
+ DEBUG_MSG(KERN_INFO "lcd_patch_skew\n");
+ switch (plvds_chip_info->output_interface) {
+ case INTERFACE_DVP0:
+ lcd_patch_skew_dvp0(plvds_setting_info, plvds_chip_info);
+ break;
+ case INTERFACE_DVP1:
+ lcd_patch_skew_dvp1(plvds_setting_info, plvds_chip_info);
+ break;
+ case INTERFACE_DFP_LOW:
+ if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
+ viafb_write_reg_mask(CR99, VIACR, 0x08,
+ BIT0 + BIT1 + BIT2 + BIT3);
+ }
+ break;
+ }
+}
+
+/* LCD Set Mode */
+void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ int video_index = plvds_setting_info->lcd_panel_size;
+ int set_iga = plvds_setting_info->iga_path;
+ int mode_bpp = plvds_setting_info->bpp;
+ int viafb_load_reg_num = 0;
+ int reg_value = 0;
+ int set_hres, set_vres;
+ int panel_hres, panel_vres;
+ u32 pll_D_N;
+ int offset;
+ struct io_register *reg = NULL;
+ struct display_timing mode_crt_reg, panel_crt_reg;
+ struct crt_mode_table *panel_crt_table = NULL;
+ struct VideoModeTable *vmode_tbl = NULL;
+
+ DEBUG_MSG(KERN_INFO "viafb_lcd_set_mode!!\n");
+ /* Get mode table */
+ mode_crt_reg = mode_crt_table->crtc;
+ /* Get panel table Pointer */
+ vmode_tbl = viafb_get_modetbl_pointer(video_index);
+ panel_crt_table = vmode_tbl->crtc;
+ panel_crt_reg = panel_crt_table->crtc;
+ DEBUG_MSG(KERN_INFO "bellow viafb_lcd_set_mode!!\n");
+ set_hres = plvds_setting_info->h_active;
+ set_vres = plvds_setting_info->v_active;
+ panel_hres = plvds_setting_info->lcd_panel_hres;
+ panel_vres = plvds_setting_info->lcd_panel_vres;
+ if (VT1636_LVDS == plvds_chip_info->lvds_chip_name)
+ viafb_init_lvds_vt1636(plvds_setting_info, plvds_chip_info);
+ plvds_setting_info->vclk = panel_crt_table->clk;
+ if (set_iga == IGA1) {
+ /* IGA1 doesn't have LCD scaling, so set it as centering. */
+ viafb_load_crtc_timing(lcd_centering_timging
+ (mode_crt_reg, panel_crt_reg), IGA1);
+ } else {
+ /* Expansion */
+ if ((plvds_setting_info->display_method ==
+ LCD_EXPANDSION) & ((set_hres != panel_hres)
+ || (set_vres != panel_vres))) {
+ /* expansion timing IGA2 loaded panel set timing*/
+ viafb_load_crtc_timing(panel_crt_reg, IGA2);
+ DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n");
+ load_lcd_scaling(set_hres, set_vres, panel_hres,
+ panel_vres);
+ DEBUG_MSG(KERN_INFO "load_lcd_scaling!!\n");
+ } else { /* Centering */
+ /* centering timing IGA2 always loaded panel
+ and mode releative timing */
+ viafb_load_crtc_timing(lcd_centering_timging
+ (mode_crt_reg, panel_crt_reg), IGA2);
+ viafb_write_reg_mask(CR79, VIACR, 0x00,
+ BIT0 + BIT1 + BIT2);
+ /* LCD scaling disabled */
+ }
+ }
+
+ if (set_iga == IGA1_IGA2) {
+ load_crtc_shadow_timing(mode_crt_reg, panel_crt_reg);
+ /* Fill shadow registers */
+
+ switch (plvds_setting_info->lcd_panel_id) {
+ case LCD_PANEL_ID0_640X480:
+ offset = 80;
+ break;
+ case LCD_PANEL_ID1_800X600:
+ case LCD_PANEL_IDA_800X480:
+ offset = 110;
+ break;
+ case LCD_PANEL_ID2_1024X768:
+ offset = 150;
+ break;
+ case LCD_PANEL_ID3_1280X768:
+ case LCD_PANEL_ID4_1280X1024:
+ case LCD_PANEL_ID5_1400X1050:
+ case LCD_PANEL_ID9_1280X800:
+ offset = 190;
+ break;
+ case LCD_PANEL_ID6_1600X1200:
+ offset = 250;
+ break;
+ case LCD_PANEL_ID7_1366X768:
+ case LCD_PANEL_IDB_1360X768:
+ offset = 212;
+ break;
+ default:
+ offset = 140;
+ break;
+ }
+
+ /* Offset for simultaneous */
+ reg_value = offset;
+ viafb_load_reg_num = offset_reg.iga2_offset_reg.reg_num;
+ reg = offset_reg.iga2_offset_reg.reg;
+ viafb_load_reg(reg_value, viafb_load_reg_num, reg, VIACR);
+ DEBUG_MSG(KERN_INFO "viafb_load_reg!!\n");
+ viafb_load_fetch_count_reg(set_hres, 4, IGA2);
+ /* Fetch count for simultaneous */
+ } else { /* SAMM */
+ /* Offset for IGA2 only */
+ viafb_load_offset_reg(set_hres, mode_bpp / 8, set_iga);
+ /* Fetch count for IGA2 only */
+ viafb_load_fetch_count_reg(set_hres, mode_bpp / 8, set_iga);
+
+ if ((viaparinfo->chip_info->gfx_chip_name != UNICHROME_CLE266)
+ && (viaparinfo->chip_info->gfx_chip_name != UNICHROME_K400))
+ viafb_load_FIFO_reg(set_iga, set_hres, set_vres);
+
+ viafb_set_color_depth(mode_bpp / 8, set_iga);
+ }
+
+ fill_lcd_format();
+
+ pll_D_N = viafb_get_clk_value(panel_crt_table[0].clk);
+ DEBUG_MSG(KERN_INFO "PLL=0x%x", pll_D_N);
+ viafb_set_vclock(pll_D_N, set_iga);
+
+ viafb_set_output_path(DEVICE_LCD, set_iga,
+ plvds_chip_info->output_interface);
+ lcd_patch_skew(plvds_setting_info, plvds_chip_info);
+
+ /* If K8M800, enable LCD Prefetch Mode. */
+ if ((viaparinfo->chip_info->gfx_chip_name == UNICHROME_K800)
+ || (UNICHROME_K8M890 == viaparinfo->chip_info->gfx_chip_name))
+ viafb_write_reg_mask(CR6A, VIACR, 0x01, BIT0);
+
+ load_lcd_patch_regs(set_hres, set_vres,
+ plvds_setting_info->lcd_panel_id, set_iga);
+
+ DEBUG_MSG(KERN_INFO "load_lcd_patch_regs!!\n");
+
+ /* Patch for non 32bit alignment mode */
+ via_pitch_alignment_patch_lcd(plvds_setting_info, plvds_chip_info);
+}
+
+static void integrated_lvds_disable(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ bool turn_off_first_powersequence = false;
+ bool turn_off_second_powersequence = false;
+ if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
+ turn_off_first_powersequence = true;
+ if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
+ turn_off_first_powersequence = true;
+ if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
+ turn_off_second_powersequence = true;
+ if (turn_off_second_powersequence) {
+ /* Use second power sequence control: */
+
+ /* Turn off power sequence. */
+ viafb_write_reg_mask(CRD4, VIACR, 0, BIT1);
+
+ /* Turn off back light. */
+ viafb_write_reg_mask(CRD3, VIACR, 0xC0, BIT6 + BIT7);
+ }
+ if (turn_off_first_powersequence) {
+ /* Use first power sequence control: */
+
+ /* Turn off power sequence. */
+ viafb_write_reg_mask(CR6A, VIACR, 0, BIT3);
+
+ /* Turn off back light. */
+ viafb_write_reg_mask(CR91, VIACR, 0xC0, BIT6 + BIT7);
+ }
+
+ /* Turn DFP High/Low Pad off. */
+ viafb_write_reg_mask(SR2A, VIASR, 0, BIT0 + BIT1 + BIT2 + BIT3);
+
+ /* Power off LVDS channel. */
+ switch (plvds_chip_info->output_interface) {
+ case INTERFACE_LVDS0:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0x80, BIT7);
+ break;
+ }
+
+ case INTERFACE_LVDS1:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0x40, BIT6);
+ break;
+ }
+
+ case INTERFACE_LVDS0LVDS1:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0xC0, BIT6 + BIT7);
+ break;
+ }
+ }
+}
+
+static void integrated_lvds_enable(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ bool turn_on_first_powersequence = false;
+ bool turn_on_second_powersequence = false;
+
+ DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
+ plvds_chip_info->output_interface);
+ if (plvds_setting_info->lcd_mode == LCD_SPWG)
+ viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
+ else
+ viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
+ if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
+ turn_on_first_powersequence = true;
+ if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
+ turn_on_first_powersequence = true;
+ if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
+ turn_on_second_powersequence = true;
+
+ if (turn_on_second_powersequence) {
+ /* Use second power sequence control: */
+
+ /* Use hardware control power sequence. */
+ viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
+
+ /* Turn on back light. */
+ viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
+
+ /* Turn on hardware power sequence. */
+ viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
+ }
+ if (turn_on_first_powersequence) {
+ /* Use first power sequence control: */
+
+ /* Use hardware control power sequence. */
+ viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
+
+ /* Turn on back light. */
+ viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
+
+ /* Turn on hardware power sequence. */
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
+ }
+
+ /* Turn DFP High/Low pad on. */
+ viafb_write_reg_mask(SR2A, VIASR, 0x0F, BIT0 + BIT1 + BIT2 + BIT3);
+
+ /* Power on LVDS channel. */
+ switch (plvds_chip_info->output_interface) {
+ case INTERFACE_LVDS0:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0, BIT7);
+ break;
+ }
+
+ case INTERFACE_LVDS1:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0, BIT6);
+ break;
+ }
+
+ case INTERFACE_LVDS0LVDS1:
+ {
+ viafb_write_reg_mask(CRD2, VIACR, 0, BIT6 + BIT7);
+ break;
+ }
+ }
+}
+
+void viafb_lcd_disable(void)
+{
+
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ lcd_powersequence_off();
+ /* DI1 pad off */
+ viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
+ } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+ if (viafb_LCD2_ON
+ && (INTEGRATED_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
+ integrated_lvds_disable(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info2);
+ if (INTEGRATED_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+ integrated_lvds_disable(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ if (VT1636_LVDS == viaparinfo->chip_info->
+ lvds_chip_info.lvds_chip_name)
+ viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ } else if (VT1636_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ viafb_disable_lvds_vt1636(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ } else {
+ /* DFP-HL pad off */
+ viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0F);
+ /* Backlight off */
+ viafb_write_reg_mask(SR3D, VIASR, 0x00, 0x20);
+ /* 24 bit DI data paht off */
+ viafb_write_reg_mask(CR91, VIACR, 0x80, 0x80);
+ /* Simultaneout disabled */
+ viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
+ }
+
+ /* Disable expansion bit */
+ viafb_write_reg_mask(CR79, VIACR, 0x00, 0x01);
+ /* CRT path set to IGA1 */
+ viafb_write_reg_mask(SR16, VIASR, 0x00, 0x40);
+ /* Simultaneout disabled */
+ viafb_write_reg_mask(CR6B, VIACR, 0x00, 0x08);
+ /* IGA2 path disabled */
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
+
+}
+
+void viafb_lcd_enable(void)
+{
+ if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266) {
+ /* DI1 pad on */
+ viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
+ lcd_powersequence_on();
+ } else if (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CX700) {
+ if (viafb_LCD2_ON && (INTEGRATED_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name))
+ integrated_lvds_enable(viaparinfo->lvds_setting_info2, \
+ &viaparinfo->chip_info->lvds_chip_info2);
+ if (INTEGRATED_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name)
+ integrated_lvds_enable(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ if (VT1636_LVDS == viaparinfo->chip_info->
+ lvds_chip_info.lvds_chip_name)
+ viafb_enable_lvds_vt1636(viaparinfo->
+ lvds_setting_info, &viaparinfo->chip_info->
+ lvds_chip_info);
+ } else if (VT1636_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ viafb_enable_lvds_vt1636(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info);
+ } else {
+ /* DFP-HL pad on */
+ viafb_write_reg_mask(SR2A, VIASR, 0x0F, 0x0F);
+ /* Backlight on */
+ viafb_write_reg_mask(SR3D, VIASR, 0x20, 0x20);
+ /* 24 bit DI data paht on */
+ viafb_write_reg_mask(CR91, VIACR, 0x00, 0x80);
+
+ /* Set data source selection bit by iga path */
+ if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+ /* DFP-H set to IGA1 */
+ viafb_write_reg_mask(CR97, VIACR, 0x00, 0x10);
+ /* DFP-L set to IGA1 */
+ viafb_write_reg_mask(CR99, VIACR, 0x00, 0x10);
+ } else {
+ /* DFP-H set to IGA2 */
+ viafb_write_reg_mask(CR97, VIACR, 0x10, 0x10);
+ /* DFP-L set to IGA2 */
+ viafb_write_reg_mask(CR99, VIACR, 0x10, 0x10);
+ }
+ /* LCD enabled */
+ viafb_write_reg_mask(CR6A, VIACR, 0x48, 0x48);
+ }
+
+ if ((viaparinfo->lvds_setting_info->iga_path == IGA1)
+ || (viaparinfo->lvds_setting_info->iga_path == IGA1_IGA2)) {
+ /* CRT path set to IGA2 */
+ viafb_write_reg_mask(SR16, VIASR, 0x40, 0x40);
+ /* IGA2 path disabled */
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x80);
+ /* IGA2 path enabled */
+ } else { /* IGA2 */
+ viafb_write_reg_mask(CR6A, VIACR, 0x80, 0x80);
+ }
+
+}
+
+static void lcd_powersequence_off(void)
+{
+ int i, mask, data;
+
+ /* Software control power sequence */
+ viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
+
+ for (i = 0; i < 3; i++) {
+ mask = PowerSequenceOff[0][i];
+ data = PowerSequenceOff[1][i] & mask;
+ viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
+ udelay(PowerSequenceOff[2][i]);
+ }
+
+ /* Disable LCD */
+ viafb_write_reg_mask(CR6A, VIACR, 0x00, 0x08);
+}
+
+static void lcd_powersequence_on(void)
+{
+ int i, mask, data;
+
+ /* Software control power sequence */
+ viafb_write_reg_mask(CR91, VIACR, 0x11, 0x11);
+
+ /* Enable LCD */
+ viafb_write_reg_mask(CR6A, VIACR, 0x08, 0x08);
+
+ for (i = 0; i < 3; i++) {
+ mask = PowerSequenceOn[0][i];
+ data = PowerSequenceOn[1][i] & mask;
+ viafb_write_reg_mask(CR91, VIACR, (u8) data, (u8) mask);
+ udelay(PowerSequenceOn[2][i]);
+ }
+
+ udelay(1);
+}
+
+static void fill_lcd_format(void)
+{
+ u8 bdithering = 0, bdual = 0;
+
+ if (viaparinfo->lvds_setting_info->device_lcd_dualedge)
+ bdual = BIT4;
+ if (viaparinfo->lvds_setting_info->LCDDithering)
+ bdithering = BIT0;
+ /* Dual & Dithering */
+ viafb_write_reg_mask(CR88, VIACR, (bdithering | bdual), BIT4 + BIT0);
+}
+
+static void check_diport_of_integrated_lvds(
+ struct lvds_chip_information *plvds_chip_info,
+ struct lvds_setting_information
+ *plvds_setting_info)
+{
+ /* Determine LCD DI Port by hardware layout. */
+ switch (viafb_display_hardware_layout) {
+ case HW_LAYOUT_LCD_ONLY:
+ {
+ if (plvds_setting_info->device_lcd_dualedge) {
+ plvds_chip_info->output_interface =
+ INTERFACE_LVDS0LVDS1;
+ } else {
+ plvds_chip_info->output_interface =
+ INTERFACE_LVDS0;
+ }
+
+ break;
+ }
+
+ case HW_LAYOUT_DVI_ONLY:
+ {
+ plvds_chip_info->output_interface = INTERFACE_NONE;
+ break;
+ }
+
+ case HW_LAYOUT_LCD1_LCD2:
+ case HW_LAYOUT_LCD_EXTERNAL_LCD2:
+ {
+ plvds_chip_info->output_interface =
+ INTERFACE_LVDS0LVDS1;
+ break;
+ }
+
+ case HW_LAYOUT_LCD_DVI:
+ {
+ plvds_chip_info->output_interface = INTERFACE_LVDS1;
+ break;
+ }
+
+ default:
+ {
+ plvds_chip_info->output_interface = INTERFACE_LVDS1;
+ break;
+ }
+ }
+
+ DEBUG_MSG(KERN_INFO
+ "Display Hardware Layout: 0x%x, LCD DI Port: 0x%x\n",
+ viafb_display_hardware_layout,
+ plvds_chip_info->output_interface);
+}
+
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+ *plvds_chip_info,
+ struct lvds_setting_information
+ *plvds_setting_info)
+{
+ if (INTERFACE_NONE != plvds_chip_info->output_interface) {
+ /*Do nothing, lcd port is specified by module parameter */
+ return;
+ }
+
+ switch (plvds_chip_info->lvds_chip_name) {
+
+ case VT1636_LVDS:
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CX700:
+ plvds_chip_info->output_interface = INTERFACE_DVP1;
+ break;
+ case UNICHROME_CN700:
+ plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
+ break;
+ default:
+ plvds_chip_info->output_interface = INTERFACE_DVP0;
+ break;
+ }
+ break;
+
+ case INTEGRATED_LVDS:
+ check_diport_of_integrated_lvds(plvds_chip_info,
+ plvds_setting_info);
+ break;
+
+ default:
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M900:
+ case UNICHROME_P4M890:
+ plvds_chip_info->output_interface = INTERFACE_DFP_LOW;
+ break;
+ default:
+ plvds_chip_info->output_interface = INTERFACE_DFP;
+ break;
+ }
+ break;
+ }
+}
+
+static struct display_timing lcd_centering_timging(struct display_timing
+ mode_crt_reg,
+ struct display_timing panel_crt_reg)
+{
+ struct display_timing crt_reg;
+
+ crt_reg.hor_total = panel_crt_reg.hor_total;
+ crt_reg.hor_addr = mode_crt_reg.hor_addr;
+ crt_reg.hor_blank_start =
+ (panel_crt_reg.hor_addr - mode_crt_reg.hor_addr) / 2 +
+ crt_reg.hor_addr;
+ crt_reg.hor_blank_end = panel_crt_reg.hor_blank_end;
+ crt_reg.hor_sync_start =
+ (panel_crt_reg.hor_sync_start -
+ panel_crt_reg.hor_blank_start) + crt_reg.hor_blank_start;
+ crt_reg.hor_sync_end = panel_crt_reg.hor_sync_end;
+
+ crt_reg.ver_total = panel_crt_reg.ver_total;
+ crt_reg.ver_addr = mode_crt_reg.ver_addr;
+ crt_reg.ver_blank_start =
+ (panel_crt_reg.ver_addr - mode_crt_reg.ver_addr) / 2 +
+ crt_reg.ver_addr;
+ crt_reg.ver_blank_end = panel_crt_reg.ver_blank_end;
+ crt_reg.ver_sync_start =
+ (panel_crt_reg.ver_sync_start -
+ panel_crt_reg.ver_blank_start) + crt_reg.ver_blank_start;
+ crt_reg.ver_sync_end = panel_crt_reg.ver_sync_end;
+
+ return crt_reg;
+}
+
+static void load_crtc_shadow_timing(struct display_timing mode_timing,
+ struct display_timing panel_timing)
+{
+ struct io_register *reg = NULL;
+ int i;
+ int viafb_load_reg_Num = 0;
+ int reg_value = 0;
+
+ if (viaparinfo->lvds_setting_info->display_method == LCD_EXPANDSION) {
+ /* Expansion */
+ for (i = 12; i < 20; i++) {
+ switch (i) {
+ case H_TOTAL_SHADOW_INDEX:
+ reg_value =
+ IGA2_HOR_TOTAL_SHADOW_FORMULA
+ (panel_timing.hor_total);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.hor_total_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
+ break;
+ case H_BLANK_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_HOR_BLANK_END_SHADOW_FORMULA
+ (panel_timing.hor_blank_start,
+ panel_timing.hor_blank_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ hor_blank_end_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ hor_blank_end_shadow.reg;
+ break;
+ case V_TOTAL_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_TOTAL_SHADOW_FORMULA
+ (panel_timing.ver_total);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_total_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
+ break;
+ case V_ADDR_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_ADDR_SHADOW_FORMULA
+ (panel_timing.ver_addr);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_addr_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
+ break;
+ case V_BLANK_SATRT_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_START_SHADOW_FORMULA
+ (panel_timing.ver_blank_start);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_blank_start_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_blank_start_shadow.reg;
+ break;
+ case V_BLANK_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_END_SHADOW_FORMULA
+ (panel_timing.ver_blank_start,
+ panel_timing.ver_blank_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_blank_end_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_blank_end_shadow.reg;
+ break;
+ case V_SYNC_SATRT_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_START_SHADOW_FORMULA
+ (panel_timing.ver_sync_start);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_sync_start_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_sync_start_shadow.reg;
+ break;
+ case V_SYNC_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_END_SHADOW_FORMULA
+ (panel_timing.ver_sync_start,
+ panel_timing.ver_sync_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_sync_end_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_sync_end_shadow.reg;
+ break;
+ }
+ viafb_load_reg(reg_value,
+ viafb_load_reg_Num, reg, VIACR);
+ }
+ } else { /* Centering */
+ for (i = 12; i < 20; i++) {
+ switch (i) {
+ case H_TOTAL_SHADOW_INDEX:
+ reg_value =
+ IGA2_HOR_TOTAL_SHADOW_FORMULA
+ (panel_timing.hor_total);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.hor_total_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.hor_total_shadow.reg;
+ break;
+ case H_BLANK_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_HOR_BLANK_END_SHADOW_FORMULA
+ (panel_timing.hor_blank_start,
+ panel_timing.hor_blank_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ hor_blank_end_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ hor_blank_end_shadow.reg;
+ break;
+ case V_TOTAL_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_TOTAL_SHADOW_FORMULA
+ (panel_timing.ver_total);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_total_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.ver_total_shadow.reg;
+ break;
+ case V_ADDR_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_ADDR_SHADOW_FORMULA
+ (mode_timing.ver_addr);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_addr_shadow.
+ reg_num;
+ reg = iga2_shadow_crtc_reg.ver_addr_shadow.reg;
+ break;
+ case V_BLANK_SATRT_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_START_SHADOW_FORMULA
+ (mode_timing.ver_blank_start);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_blank_start_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_blank_start_shadow.reg;
+ break;
+ case V_BLANK_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_BLANK_END_SHADOW_FORMULA
+ (panel_timing.ver_blank_start,
+ panel_timing.ver_blank_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.
+ ver_blank_end_shadow.reg_num;
+ reg =
+ iga2_shadow_crtc_reg.
+ ver_blank_end_shadow.reg;
+ break;
+ case V_SYNC_SATRT_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_START_SHADOW_FORMULA(
+ (panel_timing.ver_sync_start -
+ panel_timing.ver_blank_start) +
+ (panel_timing.ver_addr -
+ mode_timing.ver_addr) / 2 +
+ mode_timing.ver_addr);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_sync_start_shadow.
+ reg_num;
+ reg =
+ iga2_shadow_crtc_reg.ver_sync_start_shadow.
+ reg;
+ break;
+ case V_SYNC_END_SHADOW_INDEX:
+ reg_value =
+ IGA2_VER_SYNC_END_SHADOW_FORMULA(
+ (panel_timing.ver_sync_start -
+ panel_timing.ver_blank_start) +
+ (panel_timing.ver_addr -
+ mode_timing.ver_addr) / 2 +
+ mode_timing.ver_addr,
+ panel_timing.ver_sync_end);
+ viafb_load_reg_Num =
+ iga2_shadow_crtc_reg.ver_sync_end_shadow.
+ reg_num;
+ reg =
+ iga2_shadow_crtc_reg.ver_sync_end_shadow.
+ reg;
+ break;
+ }
+ viafb_load_reg(reg_value,
+ viafb_load_reg_Num, reg, VIACR);
+ }
+ }
+}
+
+bool viafb_lcd_get_mobile_state(bool *mobile)
+{
+ unsigned char *romptr, *tableptr;
+ u8 core_base;
+ unsigned char *biosptr;
+ /* Rom address */
+ u32 romaddr = 0x000C0000;
+ u16 start_pattern = 0;
+
+ biosptr = ioremap(romaddr, 0x10000);
+
+ memcpy(&start_pattern, biosptr, 2);
+ /* Compare pattern */
+ if (start_pattern == 0xAA55) {
+ /* Get the start of Table */
+ /* 0x1B means BIOS offset position */
+ romptr = biosptr + 0x1B;
+ tableptr = biosptr + *((u16 *) romptr);
+
+ /* Get the start of biosver structure */
+ /* 18 means BIOS version position. */
+ romptr = tableptr + 18;
+ romptr = biosptr + *((u16 *) romptr);
+
+ /* The offset should be 44, but the
+ actual image is less three char. */
+ /* pRom += 44; */
+ romptr += 41;
+
+ core_base = *romptr++;
+
+ if (core_base & 0x8)
+ *mobile = false;
+ else
+ *mobile = true;
+ /* release memory */
+ iounmap(biosptr);
+
+ return true;
+ } else {
+ iounmap(biosptr);
+ return false;
+ }
+}
+
+static void viafb_load_scaling_factor_for_p4m900(int set_hres,
+ int set_vres, int panel_hres, int panel_vres)
+{
+ int h_scaling_factor;
+ int v_scaling_factor;
+ u8 cra2 = 0;
+ u8 cr77 = 0;
+ u8 cr78 = 0;
+ u8 cr79 = 0;
+ u8 cr9f = 0;
+ /* Check if expansion for horizontal */
+ if (set_hres < panel_hres) {
+ /* Load Horizontal Scaling Factor */
+
+ /* For VIA_K8M800 or later chipsets. */
+ h_scaling_factor =
+ K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
+ /* HSCaleFactor[1:0] at CR9F[1:0] */
+ cr9f = h_scaling_factor & 0x0003;
+ /* HSCaleFactor[9:2] at CR77[7:0] */
+ cr77 = (h_scaling_factor & 0x03FC) >> 2;
+ /* HSCaleFactor[11:10] at CR79[5:4] */
+ cr79 = (h_scaling_factor & 0x0C00) >> 10;
+ cr79 <<= 4;
+
+ /* Horizontal scaling enabled */
+ cra2 = 0xC0;
+
+ DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d\n",
+ h_scaling_factor);
+ } else {
+ /* Horizontal scaling disabled */
+ cra2 = 0x00;
+ }
+
+ /* Check if expansion for vertical */
+ if (set_vres < panel_vres) {
+ /* Load Vertical Scaling Factor */
+
+ /* For VIA_K8M800 or later chipsets. */
+ v_scaling_factor =
+ K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
+
+ /* Vertical scaling enabled */
+ cra2 |= 0x08;
+ /* VSCaleFactor[0] at CR79[3] */
+ cr79 |= ((v_scaling_factor & 0x0001) << 3);
+ /* VSCaleFactor[8:1] at CR78[7:0] */
+ cr78 |= (v_scaling_factor & 0x01FE) >> 1;
+ /* VSCaleFactor[10:9] at CR79[7:6] */
+ cr79 |= ((v_scaling_factor & 0x0600) >> 9) << 6;
+
+ DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d\n",
+ v_scaling_factor);
+ } else {
+ /* Vertical scaling disabled */
+ cra2 |= 0x00;
+ }
+
+ viafb_write_reg_mask(CRA2, VIACR, cra2, BIT3 + BIT6 + BIT7);
+ viafb_write_reg_mask(CR77, VIACR, cr77, 0xFF);
+ viafb_write_reg_mask(CR78, VIACR, cr78, 0xFF);
+ viafb_write_reg_mask(CR79, VIACR, cr79, 0xF8);
+ viafb_write_reg_mask(CR9F, VIACR, cr9f, BIT0 + BIT1);
+}
diff --git a/drivers/video/via/lcd.h b/drivers/video/via/lcd.h
new file mode 100644
index 00000000000..071f47cf5be
--- /dev/null
+++ b/drivers/video/via/lcd.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __LCD_H__
+#define __LCD_H__
+
+/*Definition TMDS Device ID register*/
+#define VT1631_DEVICE_ID_REG 0x02
+#define VT1631_DEVICE_ID 0x92
+
+#define VT3271_DEVICE_ID_REG 0x02
+#define VT3271_DEVICE_ID 0x71
+
+#define GET_LCD_SIZE_BY_SYSTEM_BIOS 0x01
+#define GET_LCD_SIZE_BY_VGA_BIOS 0x02
+#define GET_LCD_SZIE_BY_HW_STRAPPING 0x03
+#define GET_LCD_SIZE_BY_USER_SETTING 0x04
+
+/* Definition DVI Panel ID*/
+/* Resolution: 640x480, Channel: single, Dithering: Enable */
+#define LCD_PANEL_ID0_640X480 0x00
+/* Resolution: 800x600, Channel: single, Dithering: Enable */
+#define LCD_PANEL_ID1_800X600 0x01
+/* Resolution: 1024x768, Channel: single, Dithering: Enable */
+#define LCD_PANEL_ID2_1024X768 0x02
+/* Resolution: 1280x768, Channel: single, Dithering: Enable */
+#define LCD_PANEL_ID3_1280X768 0x03
+/* Resolution: 1280x1024, Channel: dual, Dithering: Enable */
+#define LCD_PANEL_ID4_1280X1024 0x04
+/* Resolution: 1400x1050, Channel: dual, Dithering: Enable */
+#define LCD_PANEL_ID5_1400X1050 0x05
+/* Resolution: 1600x1200, Channel: dual, Dithering: Enable */
+#define LCD_PANEL_ID6_1600X1200 0x06
+/* Resolution: 1366x768, Channel: single, Dithering: Disable */
+#define LCD_PANEL_ID7_1366X768 0x07
+/* Resolution: 1024x600, Channel: single, Dithering: Enable*/
+#define LCD_PANEL_ID8_1024X600 0x08
+/* Resolution: 1280x800, Channel: single, Dithering: Enable*/
+#define LCD_PANEL_ID9_1280X800 0x09
+/* Resolution: 800x480, Channel: single, Dithering: Enable*/
+#define LCD_PANEL_IDA_800X480 0x0A
+/* Resolution: 1360x768, Channel: single, Dithering: Disable*/
+#define LCD_PANEL_IDB_1360X768 0x0B
+/* Resolution: 480x640, Channel: single, Dithering: Enable */
+#define LCD_PANEL_IDC_480X640 0x0C
+
+
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_lcd_disable(void);
+void viafb_lcd_enable(void);
+void viafb_init_lcd_size(void);
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+ *plvds_chip_info,
+ struct lvds_setting_information
+ *plvds_setting_info);
+void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+int viafb_lvds_trasmitter_identify(void);
+void viafb_init_lvds_output_interface(struct lvds_chip_information
+ *plvds_chip_info,
+ struct lvds_setting_information
+ *plvds_setting_info);
+bool viafb_lcd_get_mobile_state(bool *mobile);
+void viafb_load_crtc_timing(struct display_timing device_timing,
+ int set_iga);
+
+#endif /* __LCD_H__ */
diff --git a/drivers/video/via/lcdtbl.h b/drivers/video/via/lcdtbl.h
new file mode 100644
index 00000000000..6f3dd800be5
--- /dev/null
+++ b/drivers/video/via/lcdtbl.h
@@ -0,0 +1,591 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __LCDTBL_H__
+#define __LCDTBL_H__
+
+#include "share.h"
+
+/* CLE266 Software Power Sequence */
+/* {Mask}, {Data}, {Delay} */
+int PowerSequenceOn[3][3] =
+ { {0x10, 0x08, 0x06}, {0x10, 0x08, 0x06}, {0x19, 0x1FE, 0x01} };
+int PowerSequenceOff[3][3] =
+ { {0x06, 0x08, 0x10}, {0x00, 0x00, 0x00}, {0xD2, 0x19, 0x01} };
+
+/* ++++++ P880 ++++++ */
+/* Panel 1600x1200 */
+struct io_reg P880_LCD_RES_6X4_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x5E},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xD6}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR44, 0xFF, 0x7D}, {VIASR, SR45, 0xFF, 0x8C},
+ {VIASR, SR46, 0xFF, 0x02}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_6X4_16X12 ARRAY_SIZE(P880_LCD_RES_6X4_16X12)
+
+struct io_reg P880_LCD_RES_7X4_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x78},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR44, 0xFF, 0x78}, {VIASR, SR45, 0xFF, 0x8C},
+ {VIASR, SR46, 0xFF, 0x01}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_7X4_16X12 ARRAY_SIZE(P880_LCD_RES_7X4_16X12)
+
+struct io_reg P880_LCD_RES_8X6_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR44, 0xFF, 0x6D}, {VIASR, SR45, 0xFF, 0x88},
+ {VIASR, SR46, 0xFF, 0x03}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_8X6_16X12 ARRAY_SIZE(P880_LCD_RES_8X6_16X12)
+
+struct io_reg P880_LCD_RES_10X7_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xAF},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR44, 0xFF, 0x92}, {VIASR, SR45, 0xFF, 0x88},
+ {VIASR, SR46, 0xFF, 0x03}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_10X7_16X12 ARRAY_SIZE(P880_LCD_RES_10X7_16X12)
+
+struct io_reg P880_LCD_RES_12X10_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xD4},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR44, 0xFF, 0xF6}, {VIASR, SR45, 0xFF, 0x88},
+ {VIASR, SR46, 0xFF, 0x05}
+
+};
+
+#define NUM_TOTAL_P880_LCD_RES_12X10_16X12 ARRAY_SIZE(P880_LCD_RES_12X10_16X12)
+
+/* Panel 1400x1050 */
+struct io_reg P880_LCD_RES_6X4_14X10[] = {
+ /* 640x480 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x63},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR44, 0xFF, 0xC6}, {VIASR, SR45, 0xFF, 0x8C},
+ {VIASR, SR46, 0xFF, 0x05}
+};
+
+#define NUM_TOTAL_P880_LCD_RES_6X4_14X10 ARRAY_SIZE(P880_LCD_RES_6X4_14X10)
+
+struct io_reg P880_LCD_RES_8X6_14X10[] = {
+ /* 800x600 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR44, 0xFF, 0x06}, {VIASR, SR45, 0xFF, 0x8D},
+ {VIASR, SR46, 0xFF, 0x05}
+};
+
+#define NUM_TOTAL_P880_LCD_RES_8X6_14X10 ARRAY_SIZE(P880_LCD_RES_8X6_14X10)
+
+/* ++++++ K400 ++++++ */
+/* Panel 1600x1200 */
+struct io_reg K400_LCD_RES_6X4_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x73}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x73}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5A}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x5E},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xDA}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x7F}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_16X12 ARRAY_SIZE(K400_LCD_RES_6X4_16X12)
+
+struct io_reg K400_LCD_RES_7X4_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x67}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x67}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x74}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x78},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xF5}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x46}, {VIASR, SR47, 0xFF, 0x3D}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_16X12 ARRAY_SIZE(K400_LCD_RES_7X4_16X12)
+
+struct io_reg K400_LCD_RES_8X6_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xE1}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x85}, {VIASR, SR47, 0xFF, 0x6F}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_16X12 ARRAY_SIZE(K400_LCD_RES_8X6_16X12)
+
+struct io_reg K400_LCD_RES_10X7_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x65}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x65}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xAB}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xAF},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xF0}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x45}, {VIASR, SR47, 0xFF, 0x4A}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_16X12 ARRAY_SIZE(K400_LCD_RES_10X7_16X12)
+
+struct io_reg K400_LCD_RES_12X10_16X12[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x7D}, {VIACR, CR55, 0x0F, 0x08},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x7D}, {VIACR, CR54, 0x38, 0x00},
+ {VIACR, CR5D, 0x40, 0x40},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xD0}, {VIACR, CR71, 0x08, 0x00},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xD4},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xFA}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x47}, {VIASR, SR47, 0xFF, 0x7C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_16X12 ARRAY_SIZE(K400_LCD_RES_12X10_16X12)
+
+/* Panel 1400x1050 */
+struct io_reg K400_LCD_RES_6X4_14X10[] = {
+ /* 640x400 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x63},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xB4}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_14X10 ARRAY_SIZE(K400_LCD_RES_6X4_14X10)
+
+struct io_reg K400_LCD_RES_8X6_14X10[] = {
+ /* 800x600 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_14X10 ARRAY_SIZE(K400_LCD_RES_8X6_14X10)
+
+struct io_reg K400_LCD_RES_10X7_14X10[] = {
+ /* 1024x768 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xA7},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_14X10 ARRAY_SIZE(K400_LCD_RES_10X7_14X10)
+
+struct io_reg K400_LCD_RES_12X10_14X10[] = {
+ /* 1280x768, 1280x960, 1280x1024 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xD2},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_14X10 ARRAY_SIZE(K400_LCD_RES_12X10_14X10)
+
+/* ++++++ K400 ++++++ */
+/* Panel 1366x768 */
+struct io_reg K400_LCD_RES_6X4_1366X7[] = {
+ /* 640x400 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x64},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_1366X7 ARRAY_SIZE(K400_LCD_RES_6X4_1366X7)
+
+struct io_reg K400_LCD_RES_7X4_1366X7[] = {
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x75},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_1366X7 ARRAY_SIZE(K400_LCD_RES_7X4_1366X7)
+
+struct io_reg K400_LCD_RES_8X6_1366X7[] = {
+ /* 800x600 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x82},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_1366X7 ARRAY_SIZE(K400_LCD_RES_8X6_1366X7)
+
+struct io_reg K400_LCD_RES_10X7_1366X7[] = {
+ /* 1024x768 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xA7},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xC3}, {VIACR, CR67, 0x03, 0x04},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_1366X7 ARRAY_SIZE(K400_LCD_RES_10X7_1366X7)
+
+struct io_reg K400_LCD_RES_12X10_1366X7[] = {
+ /* 1280x768, 1280x960, 1280x1024 */
+ /* IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x97}, {VIACR, CR55, 0x0F, 0x56},
+ /* IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x97}, {VIACR, CR54, 0x38, 0x75},
+ {VIACR, CR5D, 0x40, 0x24},
+ /* IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xCE}, {VIACR, CR71, 0x08, 0x44},
+ /* IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xD2},
+ /* IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xC9}, {VIACR, CR67, 0x03, 0x04},
+ /* VCLK */
+ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0x79}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_12X10_1366X7\
+ ARRAY_SIZE(K400_LCD_RES_12X10_1366X7)
+
+/* ++++++ K400 ++++++ */
+/* Panel 1280x1024 */
+struct io_reg K400_LCD_RES_6X4_12X10[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+ {VIACR, CR5D, 0x40, 0x1C},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x34},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x63},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xAA}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x19}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_12X10 ARRAY_SIZE(K400_LCD_RES_6X4_12X10)
+
+struct io_reg K400_LCD_RES_7X4_12X10[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+ {VIACR, CR5D, 0x40, 0x1C},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x68}, {VIACR, CR71, 0x08, 0x34},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x6C},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xA8}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0xED}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_12X10 ARRAY_SIZE(K400_LCD_RES_7X4_12X10)
+
+struct io_reg K400_LCD_RES_8X6_12X10[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+ {VIACR, CR5D, 0x40, 0x1C},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x34},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x07}, {VIASR, SR47, 0xFF, 0x21}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_12X10 ARRAY_SIZE(K400_LCD_RES_8X6_12X10)
+
+struct io_reg K400_LCD_RES_10X7_12X10[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x9D}, {VIACR, CR55, 0x0F, 0x46},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x9D}, {VIACR, CR54, 0x38, 0x74},
+ {VIACR, CR5D, 0x40, 0x1C},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0xA3}, {VIACR, CR71, 0x08, 0x34},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0xA7},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0xBE}, {VIACR, CR67, 0x03, 0x04},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x1E}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_10X7_12X10 ARRAY_SIZE(K400_LCD_RES_10X7_12X10)
+
+/* ++++++ K400 ++++++ */
+/* Panel 1024x768 */
+struct io_reg K400_LCD_RES_6X4_10X7[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x47}, {VIACR, CR55, 0x0F, 0x35},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x47}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x60}, {VIACR, CR71, 0x08, 0x23},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x64},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x87}, {VIASR, SR47, 0xFF, 0x4C}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_10X7 ARRAY_SIZE(K400_LCD_RES_6X4_10X7)
+
+struct io_reg K400_LCD_RES_7X4_10X7[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x3B}, {VIACR, CR55, 0x0F, 0x35},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x3B}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x71}, {VIACR, CR71, 0x08, 0x23},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x75},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x96}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x05}, {VIASR, SR47, 0xFF, 0x10}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_10X7 ARRAY_SIZE(K400_LCD_RES_7X4_10X7)
+
+struct io_reg K400_LCD_RES_8X6_10X7[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x37}, {VIACR, CR55, 0x0F, 0x35},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x37}, {VIACR, CR54, 0x38, 0x2B},
+ {VIACR, CR5D, 0x40, 0x13},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7E}, {VIACR, CR71, 0x08, 0x23},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x82},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x8C}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x84}, {VIASR, SR47, 0xFF, 0xB9}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_8X6_10X7 ARRAY_SIZE(K400_LCD_RES_8X6_10X7)
+
+/* ++++++ K400 ++++++ */
+/* Panel 800x600 */
+struct io_reg K400_LCD_RES_6X4_8X6[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x1A}, {VIACR, CR55, 0x0F, 0x34},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x1A}, {VIACR, CR54, 0x38, 0xE3},
+ {VIACR, CR5D, 0x40, 0x12},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x5F}, {VIACR, CR71, 0x08, 0x22},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x63},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x6E}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0x86}, {VIASR, SR47, 0xFF, 0xB3}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_6X4_8X6 ARRAY_SIZE(K400_LCD_RES_6X4_8X6)
+
+struct io_reg K400_LCD_RES_7X4_8X6[] = {
+ /*IGA2 Horizontal Total */
+ {VIACR, CR50, 0xFF, 0x1F}, {VIACR, CR55, 0x0F, 0x34},
+ /*IGA2 Horizontal Blank End */
+ {VIACR, CR53, 0xFF, 0x1F}, {VIACR, CR54, 0x38, 0xE3},
+ {VIACR, CR5D, 0x40, 0x12},
+ /*IGA2 Horizontal Total Shadow */
+ {VIACR, CR6D, 0xFF, 0x7F}, {VIACR, CR71, 0x08, 0x22},
+ /*IGA2 Horizontal Blank End Shadow */
+ {VIACR, CR6E, 0xFF, 0x83},
+ /*IGA2 Offset */
+ {VIACR, CR66, 0xFF, 0x78}, {VIACR, CR67, 0x03, 0x00},
+ /*VCLK*/ {VIASR, SR46, 0xFF, 0xC4}, {VIASR, SR47, 0xFF, 0x59}
+};
+
+#define NUM_TOTAL_K400_LCD_RES_7X4_8X6 ARRAY_SIZE(K400_LCD_RES_7X4_8X6)
+
+#endif /* __LCDTBL_H__ */
diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h
new file mode 100644
index 00000000000..2e1254da9c8
--- /dev/null
+++ b/drivers/video/via/share.h
@@ -0,0 +1,1105 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __SHARE_H__
+#define __SHARE_H__
+
+/* Define Return Value */
+#define FAIL -1
+#define OK 1
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Define Bit Field */
+#define BIT0 0x01
+#define BIT1 0x02
+#define BIT2 0x04
+#define BIT3 0x08
+#define BIT4 0x10
+#define BIT5 0x20
+#define BIT6 0x40
+#define BIT7 0x80
+
+/* Video Memory Size */
+#define VIDEO_MEMORY_SIZE_16M 0x1000000
+
+/* Definition Mode Index
+*/
+#define VIA_RES_640X480 0
+#define VIA_RES_800X600 1
+#define VIA_RES_1024X768 2
+#define VIA_RES_1152X864 3
+#define VIA_RES_1280X1024 4
+#define VIA_RES_1600X1200 5
+#define VIA_RES_1440X1050 6
+#define VIA_RES_1280X768 7
+#define VIA_RES_1280X960 8
+#define VIA_RES_1920X1440 9
+#define VIA_RES_848X480 10
+#define VIA_RES_1400X1050 11
+#define VIA_RES_720X480 12
+#define VIA_RES_720X576 13
+#define VIA_RES_1024X512 14
+#define VIA_RES_856X480 15
+#define VIA_RES_1024X576 16
+#define VIA_RES_640X400 17
+#define VIA_RES_1280X720 18
+#define VIA_RES_1920X1080 19
+#define VIA_RES_800X480 20
+#define VIA_RES_1368X768 21
+#define VIA_RES_1024X600 22
+#define VIA_RES_1280X800 23
+#define VIA_RES_1680X1050 24
+#define VIA_RES_960X600 25
+#define VIA_RES_1000X600 26
+#define VIA_RES_1088X612 27
+#define VIA_RES_1152X720 28
+#define VIA_RES_1200X720 29
+#define VIA_RES_1280X600 30
+#define VIA_RES_1360X768 31
+#define VIA_RES_1366X768 32
+#define VIA_RES_1440X900 33
+#define VIA_RES_1600X900 34
+#define VIA_RES_1600X1024 35
+#define VIA_RES_1792X1344 36
+#define VIA_RES_1856X1392 37
+#define VIA_RES_1920X1200 38
+#define VIA_RES_2048X1536 39
+#define VIA_RES_480X640 40
+
+/*Reduce Blanking*/
+#define VIA_RES_1360X768_RB 131
+#define VIA_RES_1440X900_RB 133
+#define VIA_RES_1400X1050_RB 111
+#define VIA_RES_1600X900_RB 134
+#define VIA_RES_1680X1050_RB 124
+#define VIA_RES_1920X1080_RB 119
+#define VIA_RES_1920X1200_RB 138
+
+#define VIA_RES_INVALID 255
+
+/* standard VGA IO port
+*/
+#define VIARMisc 0x3CC
+#define VIAWMisc 0x3C2
+#define VIAStatus 0x3DA
+#define VIACR 0x3D4
+#define VIASR 0x3C4
+#define VIAGR 0x3CE
+#define VIAAR 0x3C0
+
+#define StdCR 0x19
+#define StdSR 0x04
+#define StdGR 0x09
+#define StdAR 0x14
+
+#define PatchCR 11
+
+/* Display path */
+#define IGA1 1
+#define IGA2 2
+#define IGA1_IGA2 3
+
+/* Define Color Depth */
+#define MODE_8BPP 1
+#define MODE_16BPP 2
+#define MODE_32BPP 4
+
+#define GR20 0x20
+#define GR21 0x21
+#define GR22 0x22
+
+/* Sequencer Registers */
+#define SR01 0x01
+#define SR10 0x10
+#define SR12 0x12
+#define SR15 0x15
+#define SR16 0x16
+#define SR17 0x17
+#define SR18 0x18
+#define SR1B 0x1B
+#define SR1A 0x1A
+#define SR1C 0x1C
+#define SR1D 0x1D
+#define SR1E 0x1E
+#define SR1F 0x1F
+#define SR20 0x20
+#define SR21 0x21
+#define SR22 0x22
+#define SR2A 0x2A
+#define SR2D 0x2D
+#define SR2E 0x2E
+
+#define SR30 0x30
+#define SR39 0x39
+#define SR3D 0x3D
+#define SR3E 0x3E
+#define SR3F 0x3F
+#define SR40 0x40
+#define SR43 0x43
+#define SR44 0x44
+#define SR45 0x45
+#define SR46 0x46
+#define SR47 0x47
+#define SR48 0x48
+#define SR49 0x49
+#define SR4A 0x4A
+#define SR4B 0x4B
+#define SR4C 0x4C
+#define SR52 0x52
+#define SR5E 0x5E
+#define SR65 0x65
+
+/* CRT Controller Registers */
+#define CR00 0x00
+#define CR01 0x01
+#define CR02 0x02
+#define CR03 0x03
+#define CR04 0x04
+#define CR05 0x05
+#define CR06 0x06
+#define CR07 0x07
+#define CR08 0x08
+#define CR09 0x09
+#define CR0A 0x0A
+#define CR0B 0x0B
+#define CR0C 0x0C
+#define CR0D 0x0D
+#define CR0E 0x0E
+#define CR0F 0x0F
+#define CR10 0x10
+#define CR11 0x11
+#define CR12 0x12
+#define CR13 0x13
+#define CR14 0x14
+#define CR15 0x15
+#define CR16 0x16
+#define CR17 0x17
+#define CR18 0x18
+
+/* Extend CRT Controller Registers */
+#define CR30 0x30
+#define CR31 0x31
+#define CR32 0x32
+#define CR33 0x33
+#define CR34 0x34
+#define CR35 0x35
+#define CR36 0x36
+#define CR37 0x37
+#define CR38 0x38
+#define CR39 0x39
+#define CR3A 0x3A
+#define CR3B 0x3B
+#define CR3C 0x3C
+#define CR3D 0x3D
+#define CR3E 0x3E
+#define CR3F 0x3F
+#define CR40 0x40
+#define CR41 0x41
+#define CR42 0x42
+#define CR43 0x43
+#define CR44 0x44
+#define CR45 0x45
+#define CR46 0x46
+#define CR47 0x47
+#define CR48 0x48
+#define CR49 0x49
+#define CR4A 0x4A
+#define CR4B 0x4B
+#define CR4C 0x4C
+#define CR4D 0x4D
+#define CR4E 0x4E
+#define CR4F 0x4F
+#define CR50 0x50
+#define CR51 0x51
+#define CR52 0x52
+#define CR53 0x53
+#define CR54 0x54
+#define CR55 0x55
+#define CR56 0x56
+#define CR57 0x57
+#define CR58 0x58
+#define CR59 0x59
+#define CR5A 0x5A
+#define CR5B 0x5B
+#define CR5C 0x5C
+#define CR5D 0x5D
+#define CR5E 0x5E
+#define CR5F 0x5F
+#define CR60 0x60
+#define CR61 0x61
+#define CR62 0x62
+#define CR63 0x63
+#define CR64 0x64
+#define CR65 0x65
+#define CR66 0x66
+#define CR67 0x67
+#define CR68 0x68
+#define CR69 0x69
+#define CR6A 0x6A
+#define CR6B 0x6B
+#define CR6C 0x6C
+#define CR6D 0x6D
+#define CR6E 0x6E
+#define CR6F 0x6F
+#define CR70 0x70
+#define CR71 0x71
+#define CR72 0x72
+#define CR73 0x73
+#define CR74 0x74
+#define CR75 0x75
+#define CR76 0x76
+#define CR77 0x77
+#define CR78 0x78
+#define CR79 0x79
+#define CR7A 0x7A
+#define CR7B 0x7B
+#define CR7C 0x7C
+#define CR7D 0x7D
+#define CR7E 0x7E
+#define CR7F 0x7F
+#define CR80 0x80
+#define CR81 0x81
+#define CR82 0x82
+#define CR83 0x83
+#define CR84 0x84
+#define CR85 0x85
+#define CR86 0x86
+#define CR87 0x87
+#define CR88 0x88
+#define CR89 0x89
+#define CR8A 0x8A
+#define CR8B 0x8B
+#define CR8C 0x8C
+#define CR8D 0x8D
+#define CR8E 0x8E
+#define CR8F 0x8F
+#define CR90 0x90
+#define CR91 0x91
+#define CR92 0x92
+#define CR93 0x93
+#define CR94 0x94
+#define CR95 0x95
+#define CR96 0x96
+#define CR97 0x97
+#define CR98 0x98
+#define CR99 0x99
+#define CR9A 0x9A
+#define CR9B 0x9B
+#define CR9C 0x9C
+#define CR9D 0x9D
+#define CR9E 0x9E
+#define CR9F 0x9F
+#define CRA0 0xA0
+#define CRA1 0xA1
+#define CRA2 0xA2
+#define CRA3 0xA3
+#define CRD2 0xD2
+#define CRD3 0xD3
+#define CRD4 0xD4
+
+/* LUT Table*/
+#define LUT_DATA 0x3C9 /* DACDATA */
+#define LUT_INDEX_READ 0x3C7 /* DACRX */
+#define LUT_INDEX_WRITE 0x3C8 /* DACWX */
+#define DACMASK 0x3C6
+
+/* Definition Device */
+#define DEVICE_CRT 0x01
+#define DEVICE_DVI 0x03
+#define DEVICE_LCD 0x04
+
+/* Device output interface */
+#define INTERFACE_NONE 0x00
+#define INTERFACE_ANALOG_RGB 0x01
+#define INTERFACE_DVP0 0x02
+#define INTERFACE_DVP1 0x03
+#define INTERFACE_DFP_HIGH 0x04
+#define INTERFACE_DFP_LOW 0x05
+#define INTERFACE_DFP 0x06
+#define INTERFACE_LVDS0 0x07
+#define INTERFACE_LVDS1 0x08
+#define INTERFACE_LVDS0LVDS1 0x09
+#define INTERFACE_TMDS 0x0A
+
+#define HW_LAYOUT_LCD_ONLY 0x01
+#define HW_LAYOUT_DVI_ONLY 0x02
+#define HW_LAYOUT_LCD_DVI 0x03
+#define HW_LAYOUT_LCD1_LCD2 0x04
+#define HW_LAYOUT_LCD_EXTERNAL_LCD2 0x10
+
+/* Definition Refresh Rate */
+#define REFRESH_50 50
+#define REFRESH_60 60
+#define REFRESH_75 75
+#define REFRESH_85 85
+#define REFRESH_100 100
+#define REFRESH_120 120
+
+/* Definition Sync Polarity*/
+#define NEGATIVE 1
+#define POSITIVE 0
+
+/*480x640@60 Sync Polarity (GTF)
+*/
+#define M480X640_R60_HSP NEGATIVE
+#define M480X640_R60_VSP POSITIVE
+
+/*640x480@60 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R60_HSP NEGATIVE
+#define M640X480_R60_VSP NEGATIVE
+
+/*640x480@75 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R75_HSP NEGATIVE
+#define M640X480_R75_VSP NEGATIVE
+
+/*640x480@85 Sync Polarity (VESA Mode)
+*/
+#define M640X480_R85_HSP NEGATIVE
+#define M640X480_R85_VSP NEGATIVE
+
+/*640x480@100 Sync Polarity (GTF Mode)
+*/
+#define M640X480_R100_HSP NEGATIVE
+#define M640X480_R100_VSP POSITIVE
+
+/*640x480@120 Sync Polarity (GTF Mode)
+*/
+#define M640X480_R120_HSP NEGATIVE
+#define M640X480_R120_VSP POSITIVE
+
+/*720x480@60 Sync Polarity (GTF Mode)
+*/
+#define M720X480_R60_HSP NEGATIVE
+#define M720X480_R60_VSP POSITIVE
+
+/*720x576@60 Sync Polarity (GTF Mode)
+*/
+#define M720X576_R60_HSP NEGATIVE
+#define M720X576_R60_VSP POSITIVE
+
+/*800x600@60 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R60_HSP POSITIVE
+#define M800X600_R60_VSP POSITIVE
+
+/*800x600@75 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R75_HSP POSITIVE
+#define M800X600_R75_VSP POSITIVE
+
+/*800x600@85 Sync Polarity (VESA Mode)
+*/
+#define M800X600_R85_HSP POSITIVE
+#define M800X600_R85_VSP POSITIVE
+
+/*800x600@100 Sync Polarity (GTF Mode)
+*/
+#define M800X600_R100_HSP NEGATIVE
+#define M800X600_R100_VSP POSITIVE
+
+/*800x600@120 Sync Polarity (GTF Mode)
+*/
+#define M800X600_R120_HSP NEGATIVE
+#define M800X600_R120_VSP POSITIVE
+
+/*800x480@60 Sync Polarity (CVT Mode)
+*/
+#define M800X480_R60_HSP NEGATIVE
+#define M800X480_R60_VSP POSITIVE
+
+/*848x480@60 Sync Polarity (CVT Mode)
+*/
+#define M848X480_R60_HSP NEGATIVE
+#define M848X480_R60_VSP POSITIVE
+
+/*852x480@60 Sync Polarity (GTF Mode)
+*/
+#define M852X480_R60_HSP NEGATIVE
+#define M852X480_R60_VSP POSITIVE
+
+/*1024x512@60 Sync Polarity (GTF Mode)
+*/
+#define M1024X512_R60_HSP NEGATIVE
+#define M1024X512_R60_VSP POSITIVE
+
+/*1024x600@60 Sync Polarity (GTF Mode)
+*/
+#define M1024X600_R60_HSP NEGATIVE
+#define M1024X600_R60_VSP POSITIVE
+
+/*1024x768@60 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R60_HSP NEGATIVE
+#define M1024X768_R60_VSP NEGATIVE
+
+/*1024x768@75 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R75_HSP POSITIVE
+#define M1024X768_R75_VSP POSITIVE
+
+/*1024x768@85 Sync Polarity (VESA Mode)
+*/
+#define M1024X768_R85_HSP POSITIVE
+#define M1024X768_R85_VSP POSITIVE
+
+/*1024x768@100 Sync Polarity (GTF Mode)
+*/
+#define M1024X768_R100_HSP NEGATIVE
+#define M1024X768_R100_VSP POSITIVE
+
+/*1152x864@75 Sync Polarity (VESA Mode)
+*/
+#define M1152X864_R75_HSP POSITIVE
+#define M1152X864_R75_VSP POSITIVE
+
+/*1280x720@60 Sync Polarity (GTF Mode)
+*/
+#define M1280X720_R60_HSP NEGATIVE
+#define M1280X720_R60_VSP POSITIVE
+
+/* 1280x768@50 Sync Polarity (GTF Mode) */
+#define M1280X768_R50_HSP NEGATIVE
+#define M1280X768_R50_VSP POSITIVE
+
+/*1280x768@60 Sync Polarity (GTF Mode)
+*/
+#define M1280X768_R60_HSP NEGATIVE
+#define M1280X768_R60_VSP POSITIVE
+
+/*1280x800@60 Sync Polarity (CVT Mode)
+*/
+#define M1280X800_R60_HSP NEGATIVE
+#define M1280X800_R60_VSP POSITIVE
+
+/*1280x960@60 Sync Polarity (VESA Mode)
+*/
+#define M1280X960_R60_HSP POSITIVE
+#define M1280X960_R60_VSP POSITIVE
+
+/*1280x1024@60 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R60_HSP POSITIVE
+#define M1280X1024_R60_VSP POSITIVE
+
+/* 1360x768@60 Sync Polarity (CVT Mode) */
+#define M1360X768_R60_HSP POSITIVE
+#define M1360X768_R60_VSP POSITIVE
+
+/* 1360x768@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1360X768_RB_R60_HSP POSITIVE
+#define M1360X768_RB_R60_VSP NEGATIVE
+
+/* 1368x768@50 Sync Polarity (GTF Mode) */
+#define M1368X768_R50_HSP NEGATIVE
+#define M1368X768_R50_VSP POSITIVE
+
+/* 1368x768@60 Sync Polarity (VESA Mode) */
+#define M1368X768_R60_HSP NEGATIVE
+#define M1368X768_R60_VSP POSITIVE
+
+/*1280x1024@75 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R75_HSP POSITIVE
+#define M1280X1024_R75_VSP POSITIVE
+
+/*1280x1024@85 Sync Polarity (VESA Mode)
+*/
+#define M1280X1024_R85_HSP POSITIVE
+#define M1280X1024_R85_VSP POSITIVE
+
+/*1440x1050@60 Sync Polarity (GTF Mode)
+*/
+#define M1440X1050_R60_HSP NEGATIVE
+#define M1440X1050_R60_VSP POSITIVE
+
+/*1600x1200@60 Sync Polarity (VESA Mode)
+*/
+#define M1600X1200_R60_HSP POSITIVE
+#define M1600X1200_R60_VSP POSITIVE
+
+/*1600x1200@75 Sync Polarity (VESA Mode)
+*/
+#define M1600X1200_R75_HSP POSITIVE
+#define M1600X1200_R75_VSP POSITIVE
+
+/* 1680x1050@60 Sync Polarity (CVT Mode) */
+#define M1680x1050_R60_HSP NEGATIVE
+#define M1680x1050_R60_VSP NEGATIVE
+
+/* 1680x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1680x1050_RB_R60_HSP POSITIVE
+#define M1680x1050_RB_R60_VSP NEGATIVE
+
+/* 1680x1050@75 Sync Polarity (CVT Mode) */
+#define M1680x1050_R75_HSP NEGATIVE
+#define M1680x1050_R75_VSP POSITIVE
+
+/*1920x1080@60 Sync Polarity (CVT Mode)
+*/
+#define M1920X1080_R60_HSP NEGATIVE
+#define M1920X1080_R60_VSP POSITIVE
+
+/* 1920x1080@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1920X1080_RB_R60_HSP POSITIVE
+#define M1920X1080_RB_R60_VSP NEGATIVE
+
+/*1920x1440@60 Sync Polarity (VESA Mode)
+*/
+#define M1920X1440_R60_HSP NEGATIVE
+#define M1920X1440_R60_VSP POSITIVE
+
+/*1920x1440@75 Sync Polarity (VESA Mode)
+*/
+#define M1920X1440_R75_HSP NEGATIVE
+#define M1920X1440_R75_VSP POSITIVE
+
+#if 0
+/* 1400x1050@60 Sync Polarity (VESA Mode) */
+#define M1400X1050_R60_HSP NEGATIVE
+#define M1400X1050_R60_VSP NEGATIVE
+#endif
+
+/* 1400x1050@60 Sync Polarity (CVT Mode) */
+#define M1400X1050_R60_HSP NEGATIVE
+#define M1400X1050_R60_VSP POSITIVE
+
+/* 1400x1050@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1400X1050_RB_R60_HSP POSITIVE
+#define M1400X1050_RB_R60_VSP NEGATIVE
+
+/* 1400x1050@75 Sync Polarity (CVT Mode) */
+#define M1400X1050_R75_HSP NEGATIVE
+#define M1400X1050_R75_VSP POSITIVE
+
+/* 960x600@60 Sync Polarity (CVT Mode) */
+#define M960X600_R60_HSP NEGATIVE
+#define M960X600_R60_VSP POSITIVE
+
+/* 1000x600@60 Sync Polarity (GTF Mode) */
+#define M1000X600_R60_HSP NEGATIVE
+#define M1000X600_R60_VSP POSITIVE
+
+/* 1024x576@60 Sync Polarity (GTF Mode) */
+#define M1024X576_R60_HSP NEGATIVE
+#define M1024X576_R60_VSP POSITIVE
+
+/*1024x600@60 Sync Polarity (GTF Mode)*/
+#define M1024X600_R60_HSP NEGATIVE
+#define M1024X600_R60_VSP POSITIVE
+
+/* 1088x612@60 Sync Polarity (CVT Mode) */
+#define M1088X612_R60_HSP NEGATIVE
+#define M1088X612_R60_VSP POSITIVE
+
+/* 1152x720@60 Sync Polarity (CVT Mode) */
+#define M1152X720_R60_HSP NEGATIVE
+#define M1152X720_R60_VSP POSITIVE
+
+/* 1200x720@60 Sync Polarity (GTF Mode) */
+#define M1200X720_R60_HSP NEGATIVE
+#define M1200X720_R60_VSP POSITIVE
+
+/* 1280x600@60 Sync Polarity (GTF Mode) */
+#define M1280x600_R60_HSP NEGATIVE
+#define M1280x600_R60_VSP POSITIVE
+
+/* 1280x720@50 Sync Polarity (GTF Mode) */
+#define M1280X720_R50_HSP NEGATIVE
+#define M1280X720_R50_VSP POSITIVE
+
+/* 1280x720@60 Sync Polarity (CEA Mode) */
+#define M1280X720_CEA_R60_HSP POSITIVE
+#define M1280X720_CEA_R60_VSP POSITIVE
+
+/* 1440x900@60 Sync Polarity (CVT Mode) */
+#define M1440X900_R60_HSP NEGATIVE
+#define M1440X900_R60_VSP POSITIVE
+
+/* 1440x900@75 Sync Polarity (CVT Mode) */
+#define M1440X900_R75_HSP NEGATIVE
+#define M1440X900_R75_VSP POSITIVE
+
+/* 1440x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1440X900_RB_R60_HSP POSITIVE
+#define M1440X900_RB_R60_VSP NEGATIVE
+
+/* 1600x900@60 Sync Polarity (CVT Mode) */
+#define M1600X900_R60_HSP NEGATIVE
+#define M1600X900_R60_VSP POSITIVE
+
+/* 1600x900@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1600X900_RB_R60_HSP POSITIVE
+#define M1600X900_RB_R60_VSP NEGATIVE
+
+/* 1600x1024@60 Sync Polarity (GTF Mode) */
+#define M1600X1024_R60_HSP NEGATIVE
+#define M1600X1024_R60_VSP POSITIVE
+
+/* 1792x1344@60 Sync Polarity (DMT Mode) */
+#define M1792x1344_R60_HSP NEGATIVE
+#define M1792x1344_R60_VSP POSITIVE
+
+/* 1856x1392@60 Sync Polarity (DMT Mode) */
+#define M1856x1392_R60_HSP NEGATIVE
+#define M1856x1392_R60_VSP POSITIVE
+
+/* 1920x1200@60 Sync Polarity (CVT Mode) */
+#define M1920X1200_R60_HSP NEGATIVE
+#define M1920X1200_R60_VSP POSITIVE
+
+/* 1920x1200@60 Sync Polarity (CVT Reduce Blanking Mode) */
+#define M1920X1200_RB_R60_HSP POSITIVE
+#define M1920X1200_RB_R60_VSP NEGATIVE
+
+/* 1920x1080@60 Sync Polarity (CEA Mode) */
+#define M1920X1080_CEA_R60_HSP POSITIVE
+#define M1920X1080_CEA_R60_VSP POSITIVE
+
+/* 2048x1536@60 Sync Polarity (CVT Mode) */
+#define M2048x1536_R60_HSP NEGATIVE
+#define M2048x1536_R60_VSP POSITIVE
+
+/* define PLL index: */
+#define CLK_25_175M 25175000
+#define CLK_26_880M 26880000
+#define CLK_29_581M 29581000
+#define CLK_31_490M 31490000
+#define CLK_31_500M 31500000
+#define CLK_31_728M 31728000
+#define CLK_32_668M 32688000
+#define CLK_36_000M 36000000
+#define CLK_40_000M 40000000
+#define CLK_41_291M 41291000
+#define CLK_43_163M 43163000
+#define CLK_45_250M 45250000 /* 45.46MHz */
+#define CLK_46_000M 46000000
+#define CLK_46_996M 46996000
+#define CLK_48_000M 48000000
+#define CLK_48_875M 48875000
+#define CLK_49_500M 49500000
+#define CLK_52_406M 52406000
+#define CLK_52_977M 52977000
+#define CLK_56_250M 56250000
+#define CLK_60_466M 60466000
+#define CLK_61_500M 61500000
+#define CLK_65_000M 65000000
+#define CLK_65_178M 65178000
+#define CLK_66_750M 66750000 /* 67.116MHz */
+#define CLK_68_179M 68179000
+#define CLK_69_924M 69924000
+#define CLK_70_159M 70159000
+#define CLK_72_000M 72000000
+#define CLK_74_270M 74270000
+#define CLK_78_750M 78750000
+#define CLK_80_136M 80136000
+#define CLK_83_375M 83375000
+#define CLK_83_950M 83950000
+#define CLK_84_750M 84750000 /* 84.537Mhz */
+#define CLK_85_860M 85860000
+#define CLK_88_750M 88750000
+#define CLK_94_500M 94500000
+#define CLK_97_750M 97750000
+#define CLK_101_000M 101000000
+#define CLK_106_500M 106500000
+#define CLK_108_000M 108000000
+#define CLK_113_309M 113309000
+#define CLK_118_840M 118840000
+#define CLK_119_000M 119000000
+#define CLK_121_750M 121750000 /* 121.704MHz */
+#define CLK_125_104M 125104000
+#define CLK_133_308M 133308000
+#define CLK_135_000M 135000000
+#define CLK_136_700M 136700000
+#define CLK_138_400M 138400000
+#define CLK_146_760M 146760000
+#define CLK_148_500M 148500000
+
+#define CLK_153_920M 153920000
+#define CLK_156_000M 156000000
+#define CLK_157_500M 157500000
+#define CLK_162_000M 162000000
+#define CLK_187_000M 187000000
+#define CLK_193_295M 193295000
+#define CLK_202_500M 202500000
+#define CLK_204_000M 204000000
+#define CLK_218_500M 218500000
+#define CLK_234_000M 234000000
+#define CLK_267_250M 267250000
+#define CLK_297_500M 297500000
+#define CLK_74_481M 74481000
+#define CLK_172_798M 172798000
+#define CLK_122_614M 122614000
+
+/* CLE266 PLL value
+*/
+#define CLE266_PLL_25_175M 0x0000C763
+#define CLE266_PLL_26_880M 0x0000440F
+#define CLE266_PLL_29_581M 0x00008421
+#define CLE266_PLL_31_490M 0x00004721
+#define CLE266_PLL_31_500M 0x0000C3B5
+#define CLE266_PLL_31_728M 0x0000471F
+#define CLE266_PLL_32_668M 0x0000C449
+#define CLE266_PLL_36_000M 0x0000C5E5
+#define CLE266_PLL_40_000M 0x0000C459
+#define CLE266_PLL_41_291M 0x00004417
+#define CLE266_PLL_43_163M 0x0000C579
+#define CLE266_PLL_45_250M 0x0000C57F /* 45.46MHz */
+#define CLE266_PLL_46_000M 0x0000875A
+#define CLE266_PLL_46_996M 0x0000C4E9
+#define CLE266_PLL_48_000M 0x00001443
+#define CLE266_PLL_48_875M 0x00001D63
+#define CLE266_PLL_49_500M 0x00008653
+#define CLE266_PLL_52_406M 0x0000C475
+#define CLE266_PLL_52_977M 0x00004525
+#define CLE266_PLL_56_250M 0x000047B7
+#define CLE266_PLL_60_466M 0x0000494C
+#define CLE266_PLL_61_500M 0x00001456
+#define CLE266_PLL_65_000M 0x000086ED
+#define CLE266_PLL_65_178M 0x0000855B
+#define CLE266_PLL_66_750M 0x0000844B /* 67.116MHz */
+#define CLE266_PLL_68_179M 0x00000413
+#define CLE266_PLL_69_924M 0x00001153
+#define CLE266_PLL_70_159M 0x00001462
+#define CLE266_PLL_72_000M 0x00001879
+#define CLE266_PLL_74_270M 0x00004853
+#define CLE266_PLL_78_750M 0x00004321
+#define CLE266_PLL_80_136M 0x0000051C
+#define CLE266_PLL_83_375M 0x0000C25D
+#define CLE266_PLL_83_950M 0x00000729
+#define CLE266_PLL_84_750M 0x00008576 /* 84.537MHz */
+#define CLE266_PLL_85_860M 0x00004754
+#define CLE266_PLL_88_750M 0x0000051F
+#define CLE266_PLL_94_500M 0x00000521
+#define CLE266_PLL_97_750M 0x00004652
+#define CLE266_PLL_101_000M 0x0000497F
+#define CLE266_PLL_106_500M 0x00008477 /* 106.491463 MHz */
+#define CLE266_PLL_108_000M 0x00008479
+#define CLE266_PLL_113_309M 0x00000C5F
+#define CLE266_PLL_118_840M 0x00004553
+#define CLE266_PLL_119_000M 0x00000D6C
+#define CLE266_PLL_121_750M 0x00004555 /* 121.704MHz */
+#define CLE266_PLL_125_104M 0x000006B5
+#define CLE266_PLL_133_308M 0x0000465F
+#define CLE266_PLL_135_000M 0x0000455E
+#define CLE266_PLL_136_700M 0x00000C73
+#define CLE266_PLL_138_400M 0x00000957
+#define CLE266_PLL_146_760M 0x00004567
+#define CLE266_PLL_148_500M 0x00000853
+#define CLE266_PLL_153_920M 0x00000856
+#define CLE266_PLL_156_000M 0x0000456D
+#define CLE266_PLL_157_500M 0x000005B7
+#define CLE266_PLL_162_000M 0x00004571
+#define CLE266_PLL_187_000M 0x00000976
+#define CLE266_PLL_193_295M 0x0000086C
+#define CLE266_PLL_202_500M 0x00000763
+#define CLE266_PLL_204_000M 0x00000764
+#define CLE266_PLL_218_500M 0x0000065C
+#define CLE266_PLL_234_000M 0x00000662
+#define CLE266_PLL_267_250M 0x00000670
+#define CLE266_PLL_297_500M 0x000005E6
+#define CLE266_PLL_74_481M 0x0000051A
+#define CLE266_PLL_172_798M 0x00004579
+#define CLE266_PLL_122_614M 0x0000073C
+
+/* K800 PLL value
+*/
+#define K800_PLL_25_175M 0x00539001
+#define K800_PLL_26_880M 0x001C8C80
+#define K800_PLL_29_581M 0x00409080
+#define K800_PLL_31_490M 0x006F9001
+#define K800_PLL_31_500M 0x008B9002
+#define K800_PLL_31_728M 0x00AF9003
+#define K800_PLL_32_668M 0x00909002
+#define K800_PLL_36_000M 0x009F9002
+#define K800_PLL_40_000M 0x00578C02
+#define K800_PLL_41_291M 0x00438C01
+#define K800_PLL_43_163M 0x00778C03
+#define K800_PLL_45_250M 0x007D8C83 /* 45.46MHz */
+#define K800_PLL_46_000M 0x00658C02
+#define K800_PLL_46_996M 0x00818C83
+#define K800_PLL_48_000M 0x00848C83
+#define K800_PLL_48_875M 0x00508C81
+#define K800_PLL_49_500M 0x00518C01
+#define K800_PLL_52_406M 0x00738C02
+#define K800_PLL_52_977M 0x00928C83
+#define K800_PLL_56_250M 0x007C8C02
+#define K800_PLL_60_466M 0x00A78C83
+#define K800_PLL_61_500M 0x00AA8C83
+#define K800_PLL_65_000M 0x006B8C01
+#define K800_PLL_65_178M 0x00B48C83
+#define K800_PLL_66_750M 0x00948C82 /* 67.116MHz */
+#define K800_PLL_68_179M 0x00708C01
+#define K800_PLL_69_924M 0x00C18C83
+#define K800_PLL_70_159M 0x00C28C83
+#define K800_PLL_72_000M 0x009F8C82
+#define K800_PLL_74_270M 0x00ce0c03
+#define K800_PLL_78_750M 0x00408801
+#define K800_PLL_80_136M 0x00428801
+#define K800_PLL_83_375M 0x005B0882
+#define K800_PLL_83_950M 0x00738803
+#define K800_PLL_84_750M 0x00748883 /* 84.477MHz */
+#define K800_PLL_85_860M 0x00768883
+#define K800_PLL_88_750M 0x007A8883
+#define K800_PLL_94_500M 0x00828803
+#define K800_PLL_97_750M 0x00878883
+#define K800_PLL_101_000M 0x008B8883
+#define K800_PLL_106_500M 0x00758882 /* 106.491463 MHz */
+#define K800_PLL_108_000M 0x00778882
+#define K800_PLL_113_309M 0x005D8881
+#define K800_PLL_118_840M 0x00A48883
+#define K800_PLL_119_000M 0x00838882
+#define K800_PLL_121_750M 0x00A88883 /* 121.704MHz */
+#define K800_PLL_125_104M 0x00688801
+#define K800_PLL_133_308M 0x005D8801
+#define K800_PLL_135_000M 0x001A4081
+#define K800_PLL_136_700M 0x00BD8883
+#define K800_PLL_138_400M 0x00728881
+#define K800_PLL_146_760M 0x00CC8883
+#define K800_PLL_148_500M 0x00ce0803
+#define K800_PLL_153_920M 0x00548482
+#define K800_PLL_156_000M 0x006B8483
+#define K800_PLL_157_500M 0x00142080
+#define K800_PLL_162_000M 0x006F8483
+#define K800_PLL_187_000M 0x00818483
+#define K800_PLL_193_295M 0x004F8481
+#define K800_PLL_202_500M 0x00538481
+#define K800_PLL_204_000M 0x008D8483
+#define K800_PLL_218_500M 0x00978483
+#define K800_PLL_234_000M 0x00608401
+#define K800_PLL_267_250M 0x006E8481
+#define K800_PLL_297_500M 0x00A48402
+#define K800_PLL_74_481M 0x007B8C81
+#define K800_PLL_172_798M 0x00778483
+#define K800_PLL_122_614M 0x00878882
+
+/* PLL for VT3324 */
+#define CX700_25_175M 0x008B1003
+#define CX700_26_719M 0x00931003
+#define CX700_26_880M 0x00941003
+#define CX700_29_581M 0x00A49003
+#define CX700_31_490M 0x00AE1003
+#define CX700_31_500M 0x00AE1003
+#define CX700_31_728M 0x00AF1003
+#define CX700_32_668M 0x00B51003
+#define CX700_36_000M 0x00C81003
+#define CX700_40_000M 0x006E0C03
+#define CX700_41_291M 0x00710C03
+#define CX700_43_163M 0x00770C03
+#define CX700_45_250M 0x007D0C03 /* 45.46MHz */
+#define CX700_46_000M 0x007F0C03
+#define CX700_46_996M 0x00818C83
+#define CX700_48_000M 0x00840C03
+#define CX700_48_875M 0x00508C81
+#define CX700_49_500M 0x00880C03
+#define CX700_52_406M 0x00730C02
+#define CX700_52_977M 0x00920C03
+#define CX700_56_250M 0x009B0C03
+#define CX700_60_466M 0x00460C00
+#define CX700_61_500M 0x00AA0C03
+#define CX700_65_000M 0x006B0C01
+#define CX700_65_178M 0x006B0C01
+#define CX700_66_750M 0x00940C02 /*67.116MHz */
+#define CX700_68_179M 0x00BC0C03
+#define CX700_69_924M 0x00C10C03
+#define CX700_70_159M 0x00C20C03
+#define CX700_72_000M 0x009F0C02
+#define CX700_74_270M 0x00CE0C03
+#define CX700_74_481M 0x00CE0C03
+#define CX700_78_750M 0x006C0803
+#define CX700_80_136M 0x006E0803
+#define CX700_83_375M 0x005B0882
+#define CX700_83_950M 0x00730803
+#define CX700_84_750M 0x00740803 /* 84.537Mhz */
+#define CX700_85_860M 0x00760803
+#define CX700_88_750M 0x00AC8885
+#define CX700_94_500M 0x00820803
+#define CX700_97_750M 0x00870803
+#define CX700_101_000M 0x008B0803
+#define CX700_106_500M 0x00750802
+#define CX700_108_000M 0x00950803
+#define CX700_113_309M 0x005D0801
+#define CX700_118_840M 0x00A40803
+#define CX700_119_000M 0x00830802
+#define CX700_121_750M 0x00420800 /* 121.704MHz */
+#define CX700_125_104M 0x00AD0803
+#define CX700_133_308M 0x00930802
+#define CX700_135_000M 0x00950802
+#define CX700_136_700M 0x00BD0803
+#define CX700_138_400M 0x00720801
+#define CX700_146_760M 0x00CC0803
+#define CX700_148_500M 0x00a40802
+#define CX700_153_920M 0x00540402
+#define CX700_156_000M 0x006B0403
+#define CX700_157_500M 0x006C0403
+#define CX700_162_000M 0x006F0403
+#define CX700_172_798M 0x00770403
+#define CX700_187_000M 0x00810403
+#define CX700_193_295M 0x00850403
+#define CX700_202_500M 0x008C0403
+#define CX700_204_000M 0x008D0403
+#define CX700_218_500M 0x00970403
+#define CX700_234_000M 0x00600401
+#define CX700_267_250M 0x00B90403
+#define CX700_297_500M 0x00CE0403
+#define CX700_122_614M 0x00870802
+
+/* Definition CRTC Timing Index */
+#define H_TOTAL_INDEX 0
+#define H_ADDR_INDEX 1
+#define H_BLANK_START_INDEX 2
+#define H_BLANK_END_INDEX 3
+#define H_SYNC_START_INDEX 4
+#define H_SYNC_END_INDEX 5
+#define V_TOTAL_INDEX 6
+#define V_ADDR_INDEX 7
+#define V_BLANK_START_INDEX 8
+#define V_BLANK_END_INDEX 9
+#define V_SYNC_START_INDEX 10
+#define V_SYNC_END_INDEX 11
+#define H_TOTAL_SHADOW_INDEX 12
+#define H_BLANK_END_SHADOW_INDEX 13
+#define V_TOTAL_SHADOW_INDEX 14
+#define V_ADDR_SHADOW_INDEX 15
+#define V_BLANK_SATRT_SHADOW_INDEX 16
+#define V_BLANK_END_SHADOW_INDEX 17
+#define V_SYNC_SATRT_SHADOW_INDEX 18
+#define V_SYNC_END_SHADOW_INDEX 19
+
+/* Definition Video Mode Pixel Clock (picoseconds)
+*/
+#define RES_480X640_60HZ_PIXCLOCK 39722
+#define RES_640X480_60HZ_PIXCLOCK 39722
+#define RES_640X480_75HZ_PIXCLOCK 31747
+#define RES_640X480_85HZ_PIXCLOCK 27777
+#define RES_640X480_100HZ_PIXCLOCK 23168
+#define RES_640X480_120HZ_PIXCLOCK 19081
+#define RES_720X480_60HZ_PIXCLOCK 37020
+#define RES_720X576_60HZ_PIXCLOCK 30611
+#define RES_800X600_60HZ_PIXCLOCK 25000
+#define RES_800X600_75HZ_PIXCLOCK 20203
+#define RES_800X600_85HZ_PIXCLOCK 17777
+#define RES_800X600_100HZ_PIXCLOCK 14667
+#define RES_800X600_120HZ_PIXCLOCK 11912
+#define RES_800X480_60HZ_PIXCLOCK 33805
+#define RES_848X480_60HZ_PIXCLOCK 31756
+#define RES_856X480_60HZ_PIXCLOCK 31518
+#define RES_1024X512_60HZ_PIXCLOCK 24218
+#define RES_1024X600_60HZ_PIXCLOCK 20460
+#define RES_1024X768_60HZ_PIXCLOCK 15385
+#define RES_1024X768_75HZ_PIXCLOCK 12699
+#define RES_1024X768_85HZ_PIXCLOCK 10582
+#define RES_1024X768_100HZ_PIXCLOCK 8825
+#define RES_1152X864_75HZ_PIXCLOCK 9259
+#define RES_1280X768_60HZ_PIXCLOCK 12480
+#define RES_1280X800_60HZ_PIXCLOCK 11994
+#define RES_1280X960_60HZ_PIXCLOCK 9259
+#define RES_1280X1024_60HZ_PIXCLOCK 9260
+#define RES_1280X1024_75HZ_PIXCLOCK 7408
+#define RES_1280X768_85HZ_PIXCLOCK 6349
+#define RES_1440X1050_60HZ_PIXCLOCK 7993
+#define RES_1600X1200_60HZ_PIXCLOCK 6172
+#define RES_1600X1200_75HZ_PIXCLOCK 4938
+#define RES_1280X720_60HZ_PIXCLOCK 13426
+#define RES_1920X1080_60HZ_PIXCLOCK 5787
+#define RES_1400X1050_60HZ_PIXCLOCK 8214
+#define RES_1400X1050_75HZ_PIXCLOCK 6410
+#define RES_1368X768_60HZ_PIXCLOCK 11647
+#define RES_960X600_60HZ_PIXCLOCK 22099
+#define RES_1000X600_60HZ_PIXCLOCK 20834
+#define RES_1024X576_60HZ_PIXCLOCK 21278
+#define RES_1088X612_60HZ_PIXCLOCK 18877
+#define RES_1152X720_60HZ_PIXCLOCK 14981
+#define RES_1200X720_60HZ_PIXCLOCK 14253
+#define RES_1280X600_60HZ_PIXCLOCK 16260
+#define RES_1280X720_50HZ_PIXCLOCK 16538
+#define RES_1280X768_50HZ_PIXCLOCK 15342
+#define RES_1366X768_50HZ_PIXCLOCK 14301
+#define RES_1366X768_60HZ_PIXCLOCK 11646
+#define RES_1360X768_60HZ_PIXCLOCK 11799
+#define RES_1440X900_60HZ_PIXCLOCK 9390
+#define RES_1440X900_75HZ_PIXCLOCK 7315
+#define RES_1600X900_60HZ_PIXCLOCK 8415
+#define RES_1600X1024_60HZ_PIXCLOCK 7315
+#define RES_1680X1050_60HZ_PIXCLOCK 6814
+#define RES_1680X1050_75HZ_PIXCLOCK 5348
+#define RES_1792X1344_60HZ_PIXCLOCK 4902
+#define RES_1856X1392_60HZ_PIXCLOCK 4577
+#define RES_1920X1200_60HZ_PIXCLOCK 5173
+#define RES_1920X1440_60HZ_PIXCLOCK 4274
+#define RES_1920X1440_75HZ_PIXCLOCK 3367
+#define RES_2048X1536_60HZ_PIXCLOCK 3742
+
+#define RES_1360X768_RB_60HZ_PIXCLOCK 13889
+#define RES_1400X1050_RB_60HZ_PIXCLOCK 9901
+#define RES_1440X900_RB_60HZ_PIXCLOCK 11268
+#define RES_1600X900_RB_60HZ_PIXCLOCK 10230
+#define RES_1680X1050_RB_60HZ_PIXCLOCK 8403
+#define RES_1920X1080_RB_60HZ_PIXCLOCK 7225
+#define RES_1920X1200_RB_60HZ_PIXCLOCK 6497
+
+/* LCD display method
+*/
+#define LCD_EXPANDSION 0x00
+#define LCD_CENTERING 0x01
+
+/* LCD mode
+*/
+#define LCD_OPENLDI 0x00
+#define LCD_SPWG 0x01
+
+/* Define display timing
+*/
+struct display_timing {
+ u16 hor_total;
+ u16 hor_addr;
+ u16 hor_blank_start;
+ u16 hor_blank_end;
+ u16 hor_sync_start;
+ u16 hor_sync_end;
+ u16 ver_total;
+ u16 ver_addr;
+ u16 ver_blank_start;
+ u16 ver_blank_end;
+ u16 ver_sync_start;
+ u16 ver_sync_end;
+};
+
+struct crt_mode_table {
+ int refresh_rate;
+ unsigned long clk;
+ int h_sync_polarity;
+ int v_sync_polarity;
+ struct display_timing crtc;
+};
+
+struct io_reg {
+ int port;
+ u8 index;
+ u8 mask;
+ u8 value;
+};
+
+#endif /* __SHARE_H__ */
diff --git a/drivers/video/via/tbl1636.c b/drivers/video/via/tbl1636.c
new file mode 100644
index 00000000000..2d8453429d4
--- /dev/null
+++ b/drivers/video/via/tbl1636.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+struct IODATA COMMON_INIT_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ /* Set panel power sequence timing */
+ {0x10, 0xC0, 0x00},
+ /* T1: VDD on - Data on. Each increment is 1 ms. (50ms = 031h) */
+ {0x0B, 0xFF, 0x40},
+ /* T2: Data on - Backlight on. Each increment is 2 ms. (210ms = 068h) */
+ {0x0C, 0xFF, 0x31},
+ /* T3: Backlight off -Data off. Each increment is 2 ms. (210ms = 068h)*/
+ {0x0D, 0xFF, 0x31},
+ /* T4: Data off - VDD off. Each increment is 1 ms. (50ms = 031h) */
+ {0x0E, 0xFF, 0x68},
+ /* T5: VDD off - VDD on. Each increment is 100 ms. (500ms = 04h) */
+ {0x0F, 0xFF, 0x68},
+ /* LVDS output power up */
+ {0x09, 0xA0, 0xA0},
+ /* turn on back light */
+ {0x10, 0x33, 0x13}
+};
+
+struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x08, 0xF0, 0xE0} /* Input Data Mode Select */
+};
+
+struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x08, 0xF0, 0x00} /* Input Data Mode Select */
+};
+
+struct IODATA DITHERING_ENABLE_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x0A, 0x70, 0x50}
+};
+
+struct IODATA DITHERING_DISABLE_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x0A, 0x70, 0x00}
+};
+
+struct IODATA VDD_ON_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x10, 0x20, 0x20}
+};
+
+struct IODATA VDD_OFF_TBL_VT1636[] = {
+/* Index, Mask, Value */
+ {0x10, 0x20, 0x00}
+};
diff --git a/drivers/video/via/tbl1636.h b/drivers/video/via/tbl1636.h
new file mode 100644
index 00000000000..d906055f151
--- /dev/null
+++ b/drivers/video/via/tbl1636.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 _TBL1636_H_
+#define _TBL1636_H_
+#include "hw.h"
+
+extern struct IODATA COMMON_INIT_TBL_VT1636[8];
+extern struct IODATA DUAL_CHANNEL_ENABLE_TBL_VT1636[1];
+extern struct IODATA SINGLE_CHANNEL_ENABLE_TBL_VT1636[1];
+extern struct IODATA DITHERING_ENABLE_TBL_VT1636[1];
+extern struct IODATA DITHERING_DISABLE_TBL_VT1636[1];
+extern struct IODATA VDD_ON_TBL_VT1636[1];
+extern struct IODATA VDD_OFF_TBL_VT1636[1];
+
+#endif /* _VIA_TBL1636_H_ */
diff --git a/drivers/video/via/tblDPASetting.c b/drivers/video/via/tblDPASetting.c
new file mode 100644
index 00000000000..0c4c8cc712f
--- /dev/null
+++ b/drivers/video/via/tblDPASetting.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+/* For VT3324: */
+struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[] = {
+ /* Panel ID, CLK_SEL_ST1[09], CLK_SEL_ST2[08] */
+ {LCD_PANEL_ID0_640X480, 0x00, 0x00}, /* For 640x480 */
+ {LCD_PANEL_ID1_800X600, 0x00, 0x00}, /* For 800x600 */
+ {LCD_PANEL_ID2_1024X768, 0x00, 0x00}, /* For 1024x768 */
+ {LCD_PANEL_ID3_1280X768, 0x00, 0x00}, /* For 1280x768 */
+ {LCD_PANEL_ID4_1280X1024, 0x00, 0x00}, /* For 1280x1024 */
+ {LCD_PANEL_ID5_1400X1050, 0x00, 0x00}, /* For 1400x1050 */
+ {LCD_PANEL_ID6_1600X1200, 0x0B, 0x03} /* For 1600x1200 */
+};
+
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[] = {
+/* ClkRange, DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
+ DVP1Driving, DFPHigh, DFPLow */
+/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+ SR65, CR97, CR99 */
+ /* LCK/VCK < 30000000 will use this value */
+ {DPA_CLK_RANGE_30M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00},
+ /* 30000000 < LCK/VCK < 50000000 will use this value */
+ {DPA_CLK_RANGE_30_50M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00,
+ 0x00},
+ /* 50000000 < LCK/VCK < 70000000 will use this value */
+ {DPA_CLK_RANGE_50_70M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00},
+ /* 70000000 < LCK/VCK < 100000000 will use this value */
+ {DPA_CLK_RANGE_70_100M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00},
+ /* 100000000 < LCK/VCK < 15000000 will use this value */
+ {DPA_CLK_RANGE_100_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+ 0x00},
+ /* 15000000 < LCK/VCK will use this value */
+ {DPA_CLK_RANGE_150M, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0E, 0x00,
+ 0x00},
+};
+
+/* For VT3327: */
+struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[] = {
+ /* Panel ID, CLK_SEL_ST1[09], CLK_SEL_ST2[08] */
+ {LCD_PANEL_ID0_640X480, 0x00, 0x00}, /* For 640x480 */
+ {LCD_PANEL_ID1_800X600, 0x00, 0x00}, /* For 800x600 */
+ {LCD_PANEL_ID2_1024X768, 0x00, 0x00}, /* For 1024x768 */
+ {LCD_PANEL_ID3_1280X768, 0x00, 0x00}, /* For 1280x768 */
+ {LCD_PANEL_ID4_1280X1024, 0x00, 0x00}, /* For 1280x1024 */
+ {LCD_PANEL_ID5_1400X1050, 0x00, 0x00}, /* For 1400x1050 */
+ {LCD_PANEL_ID6_1600X1200, 0x00, 0x00} /* For 1600x1200 */
+};
+
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[] = {
+/* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
+ DVP1Driving, DFPHigh, DFPLow */
+/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+ SR65, CR97, CR99 */
+/* LCK/VCK < 30000000 will use this value */
+{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 30000000 < LCK/VCK < 50000000 will use this value */
+{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 50000000 < LCK/VCK < 70000000 will use this value */
+{DPA_CLK_RANGE_50_70M, 0x06, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x01},
+/* 70000000 < LCK/VCK < 100000000 will use this value */
+{DPA_CLK_RANGE_70_100M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x03},
+/* 100000000 < LCK/VCK < 15000000 will use this value */
+{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x02},
+/* 15000000 < LCK/VCK will use this value */
+{DPA_CLK_RANGE_150M, 0x00, 0x20, 0x00, 0x10, 0x00, 0x03, 0x00, 0x0D, 0x03},
+};
+
+/* For VT3364: */
+struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[] = {
+/* ClkRange,DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
+ DVP1Driving, DFPHigh, DFPLow */
+/* CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2], CR9B,
+ SR65, CR97, CR99 */
+/* LCK/VCK < 30000000 will use this value */
+{DPA_CLK_RANGE_30M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 30000000 < LCK/VCK < 50000000 will use this value */
+{DPA_CLK_RANGE_30_50M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 50000000 < LCK/VCK < 70000000 will use this value */
+{DPA_CLK_RANGE_50_70M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 70000000 < LCK/VCK < 100000000 will use this value */
+{DPA_CLK_RANGE_70_100M, 0x07, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 100000000 < LCK/VCK < 15000000 will use this value */
+{DPA_CLK_RANGE_100_150M, 0x03, 0x00, 0x02, 0x00, 0x00, 0x03, 0x00, 0x00, 0x08},
+/* 15000000 < LCK/VCK will use this value */
+{DPA_CLK_RANGE_150M, 0x01, 0x00, 0x02, 0x10, 0x00, 0x03, 0x00, 0x00, 0x08},
+};
diff --git a/drivers/video/via/tblDPASetting.h b/drivers/video/via/tblDPASetting.h
new file mode 100644
index 00000000000..b065a83481d
--- /dev/null
+++ b/drivers/video/via/tblDPASetting.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 _TBLDPASETTING_H_
+#define _TBLDPASETTING_H_
+#include "global.h"
+
+#define DPA_CLK_30M 30000000
+#define DPA_CLK_50M 50000000
+#define DPA_CLK_70M 70000000
+#define DPA_CLK_100M 100000000
+#define DPA_CLK_150M 150000000
+
+enum DPA_RANGE {
+ DPA_CLK_RANGE_30M,
+ DPA_CLK_RANGE_30_50M,
+ DPA_CLK_RANGE_50_70M,
+ DPA_CLK_RANGE_70_100M,
+ DPA_CLK_RANGE_100_150M,
+ DPA_CLK_RANGE_150M
+};
+
+extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3324[7];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3324[6];
+extern struct VT1636_DPA_SETTING VT1636_DPA_SETTING_TBL_VT3327[7];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3327[];
+extern struct GFX_DPA_SETTING GFX_DPA_SETTING_TBL_VT3364[6];
+
+#endif
diff --git a/drivers/video/via/via_i2c.c b/drivers/video/via/via_i2c.c
new file mode 100644
index 00000000000..0f3ed4eb236
--- /dev/null
+++ b/drivers/video/via/via_i2c.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+static void via_i2c_setscl(void *data, int state)
+{
+ u8 val;
+ struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+ val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+ if (state)
+ val |= 0x20;
+ else
+ val &= ~0x20;
+ switch (via_i2c_chan->i2c_port) {
+ case I2CPORTINDEX:
+ val |= 0x01;
+ break;
+ case GPIOPORTINDEX:
+ val |= 0x80;
+ break;
+ default:
+ DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+ }
+ viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+}
+
+static int via_i2c_getscl(void *data)
+{
+ struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+ if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x08)
+ return 1;
+ return 0;
+}
+
+static int via_i2c_getsda(void *data)
+{
+ struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+ if (viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0x04)
+ return 1;
+ return 0;
+}
+
+static void via_i2c_setsda(void *data, int state)
+{
+ u8 val;
+ struct via_i2c_stuff *via_i2c_chan = (struct via_i2c_stuff *)data;
+
+ val = viafb_read_reg(VIASR, via_i2c_chan->i2c_port) & 0xF0;
+ if (state)
+ val |= 0x10;
+ else
+ val &= ~0x10;
+ switch (via_i2c_chan->i2c_port) {
+ case I2CPORTINDEX:
+ val |= 0x01;
+ break;
+ case GPIOPORTINDEX:
+ val |= 0x40;
+ break;
+ default:
+ DEBUG_MSG("via_i2c: specify wrong i2c port.\n");
+ }
+ viafb_write_reg(via_i2c_chan->i2c_port, VIASR, val);
+}
+
+int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata)
+{
+ u8 mm1[] = {0x00};
+ struct i2c_msg msgs[2];
+
+ *pdata = 0;
+ msgs[0].flags = 0;
+ msgs[1].flags = I2C_M_RD;
+ msgs[0].addr = msgs[1].addr = slave_addr / 2;
+ mm1[0] = index;
+ msgs[0].len = 1; msgs[1].len = 1;
+ msgs[0].buf = mm1; msgs[1].buf = pdata;
+ i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2);
+
+ return 0;
+}
+
+int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data)
+{
+ u8 msg[2] = { index, data };
+ struct i2c_msg msgs;
+
+ msgs.flags = 0;
+ msgs.addr = slave_addr / 2;
+ msgs.len = 2;
+ msgs.buf = msg;
+ return i2c_transfer(&viaparinfo->i2c_stuff.adapter, &msgs, 1);
+}
+
+int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len)
+{
+ u8 mm1[] = {0x00};
+ struct i2c_msg msgs[2];
+
+ msgs[0].flags = 0;
+ msgs[1].flags = I2C_M_RD;
+ msgs[0].addr = msgs[1].addr = slave_addr / 2;
+ mm1[0] = index;
+ msgs[0].len = 1; msgs[1].len = buff_len;
+ msgs[0].buf = mm1; msgs[1].buf = buff;
+ i2c_transfer(&viaparinfo->i2c_stuff.adapter, msgs, 2);
+ return 0;
+}
+
+int viafb_create_i2c_bus(void *viapar)
+{
+ int ret;
+ struct viafb_par *par = (struct viafb_par *)viapar;
+
+ strcpy(par->i2c_stuff.adapter.name, "via_i2c");
+ par->i2c_stuff.i2c_port = 0x0;
+ par->i2c_stuff.adapter.owner = THIS_MODULE;
+ par->i2c_stuff.adapter.id = 0x01FFFF;
+ par->i2c_stuff.adapter.class = 0;
+ par->i2c_stuff.adapter.algo_data = &par->i2c_stuff.algo;
+ par->i2c_stuff.adapter.dev.parent = NULL;
+ par->i2c_stuff.algo.setsda = via_i2c_setsda;
+ par->i2c_stuff.algo.setscl = via_i2c_setscl;
+ par->i2c_stuff.algo.getsda = via_i2c_getsda;
+ par->i2c_stuff.algo.getscl = via_i2c_getscl;
+ par->i2c_stuff.algo.udelay = 40;
+ par->i2c_stuff.algo.timeout = 20;
+ par->i2c_stuff.algo.data = &par->i2c_stuff;
+
+ i2c_set_adapdata(&par->i2c_stuff.adapter, &par->i2c_stuff);
+
+ /* Raise SCL and SDA */
+ par->i2c_stuff.i2c_port = I2CPORTINDEX;
+ via_i2c_setsda(&par->i2c_stuff, 1);
+ via_i2c_setscl(&par->i2c_stuff, 1);
+
+ par->i2c_stuff.i2c_port = GPIOPORTINDEX;
+ via_i2c_setsda(&par->i2c_stuff, 1);
+ via_i2c_setscl(&par->i2c_stuff, 1);
+ udelay(20);
+
+ ret = i2c_bit_add_bus(&par->i2c_stuff.adapter);
+ if (ret == 0)
+ DEBUG_MSG("I2C bus %s registered.\n",
+ par->i2c_stuff.adapter.name);
+ else
+ DEBUG_MSG("Failed to register I2C bus %s.\n",
+ par->i2c_stuff.adapter.name);
+ return ret;
+}
+
+void viafb_delete_i2c_buss(void *par)
+{
+ i2c_del_adapter(&((struct viafb_par *)par)->i2c_stuff.adapter);
+}
diff --git a/drivers/video/via/via_i2c.h b/drivers/video/via/via_i2c.h
new file mode 100644
index 00000000000..3a13242a315
--- /dev/null
+++ b/drivers/video/via/via_i2c.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __VIA_I2C_H__
+#define __VIA_I2C_H__
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+
+struct via_i2c_stuff {
+ u16 i2c_port; /* GPIO or I2C port */
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo;
+};
+
+#define I2CPORT 0x3c4
+#define I2CPORTINDEX 0x31
+#define GPIOPORT 0x3C4
+#define GPIOPORTINDEX 0x2C
+#define I2C_BUS 1
+#define GPIO_BUS 2
+#define DELAYPORT 0x3C3
+
+int viafb_i2c_readbyte(u8 slave_addr, u8 index, u8 *pdata);
+int viafb_i2c_writebyte(u8 slave_addr, u8 index, u8 data);
+int viafb_i2c_readbytes(u8 slave_addr, u8 index, u8 *buff, int buff_len);
+int viafb_create_i2c_bus(void *par);
+void viafb_delete_i2c_buss(void *par);
+#endif /* __VIA_I2C_H__ */
diff --git a/drivers/video/via/via_utility.c b/drivers/video/via/via_utility.c
new file mode 100644
index 00000000000..d53c3d54ed8
--- /dev/null
+++ b/drivers/video/via/via_utility.c
@@ -0,0 +1,253 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+void viafb_get_device_support_state(u32 *support_state)
+{
+ *support_state = CRT_Device;
+
+ if (viaparinfo->chip_info->tmds_chip_info.tmds_chip_name == VT1632_TMDS)
+ *support_state |= DVI_Device;
+
+ if (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name == VT1631_LVDS)
+ *support_state |= LCD_Device;
+}
+
+void viafb_get_device_connect_state(u32 *connect_state)
+{
+ bool mobile = false;
+
+ *connect_state = CRT_Device;
+
+ if (viafb_dvi_sense())
+ *connect_state |= DVI_Device;
+
+ viafb_lcd_get_mobile_state(&mobile);
+ if (mobile)
+ *connect_state |= LCD_Device;
+}
+
+bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres)
+{
+ unsigned int support_state = 0;
+
+ switch (viafb_lcd_panel_id) {
+ case LCD_PANEL_ID0_640X480:
+ if ((xres < 640) && (yres < 480))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID1_800X600:
+ if ((xres < 800) && (yres < 600))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID2_1024X768:
+ if ((xres < 1024) && (yres < 768))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID3_1280X768:
+ if ((xres < 1280) && (yres < 768))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID4_1280X1024:
+ if ((xres < 1280) && (yres < 1024))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID5_1400X1050:
+ if ((xres < 1400) && (yres < 1050))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID6_1600X1200:
+ if ((xres < 1600) && (yres < 1200))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID7_1366X768:
+ if ((xres < 1366) && (yres < 768))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID8_1024X600:
+ if ((xres < 1024) && (yres < 600))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_ID9_1280X800:
+ if ((xres < 1280) && (yres < 800))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_IDA_800X480:
+ if ((xres < 800) && (yres < 480))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_IDB_1360X768:
+ if ((xres < 1360) && (yres < 768))
+ support_state = true;
+ break;
+
+ case LCD_PANEL_IDC_480X640:
+ if ((xres < 480) && (yres < 640))
+ support_state = true;
+ break;
+
+ default:
+ support_state = false;
+ break;
+ }
+
+ return support_state;
+}
+
+/*====================================================================*/
+/* Gamma Function Implementation*/
+/*====================================================================*/
+
+void viafb_set_gamma_table(int bpp, unsigned int *gamma_table)
+{
+ int i, sr1a;
+ int active_device_amount = 0;
+ int device_status = viafb_DeviceStatus;
+
+ for (i = 0; i < sizeof(viafb_DeviceStatus) * 8; i++) {
+ if (device_status & 1)
+ active_device_amount++;
+ device_status >>= 1;
+ }
+
+ /* 8 bpp mode can't adjust gamma */
+ if (bpp == 8)
+ return ;
+
+ /* Enable Gamma */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7);
+ break;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7);
+ break;
+ }
+ sr1a = (unsigned int)viafb_read_reg(VIASR, SR1A);
+ viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0);
+
+ /* Fill IGA1 Gamma Table */
+ outb(0, LUT_INDEX_WRITE);
+ for (i = 0; i < 256; i++) {
+ outb(gamma_table[i] >> 16, LUT_DATA);
+ outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA);
+ outb(gamma_table[i] & 0xFF, LUT_DATA);
+ }
+
+ /* If adjust Gamma value in SAMM, fill IGA1,
+ IGA2 Gamma table simultanous. */
+ /* Switch to IGA2 Gamma Table */
+ if ((active_device_amount > 1) &&
+ !((viaparinfo->chip_info->gfx_chip_name ==
+ UNICHROME_CLE266) &&
+ (viaparinfo->chip_info->gfx_chip_revision < 15))) {
+ viafb_write_reg_mask(SR1A, VIASR, 0x01, BIT0);
+ viafb_write_reg_mask(CR6A, VIACR, 0x02, BIT1);
+
+ /* Fill IGA2 Gamma Table */
+ outb(0, LUT_INDEX_WRITE);
+ for (i = 0; i < 256; i++) {
+ outb(gamma_table[i] >> 16, LUT_DATA);
+ outb(gamma_table[i] >> 8 & 0xFF, LUT_DATA);
+ outb(gamma_table[i] & 0xFF, LUT_DATA);
+ }
+ }
+ viafb_write_reg(SR1A, VIASR, sr1a);
+}
+
+void viafb_get_gamma_table(unsigned int *gamma_table)
+{
+ unsigned char color_r, color_g, color_b;
+ unsigned char sr1a = 0;
+ int i;
+
+ /* Enable Gamma */
+ switch (viaparinfo->chip_info->gfx_chip_name) {
+ case UNICHROME_CLE266:
+ case UNICHROME_K400:
+ viafb_write_reg_mask(SR16, VIASR, 0x80, BIT7);
+ break;
+
+ case UNICHROME_K800:
+ case UNICHROME_PM800:
+ case UNICHROME_CN700:
+ case UNICHROME_CX700:
+ case UNICHROME_K8M890:
+ case UNICHROME_P4M890:
+ case UNICHROME_P4M900:
+ viafb_write_reg_mask(CR33, VIACR, 0x80, BIT7);
+ break;
+ }
+ sr1a = viafb_read_reg(VIASR, SR1A);
+ viafb_write_reg_mask(SR1A, VIASR, 0x0, BIT0);
+
+ /* Reading gamma table to get color value */
+ outb(0, LUT_INDEX_READ);
+ for (i = 0; i < 256; i++) {
+ color_r = inb(LUT_DATA);
+ color_g = inb(LUT_DATA);
+ color_b = inb(LUT_DATA);
+ gamma_table[i] =
+ ((((u32) color_r) << 16) |
+ (((u16) color_g) << 8)) | color_b;
+ }
+ viafb_write_reg(SR1A, VIASR, sr1a);
+}
+
+void viafb_get_gamma_support_state(int bpp, unsigned int *support_state)
+{
+ if (bpp == 8)
+ *support_state = None_Device;
+ else
+ *support_state = CRT_Device | DVI_Device | LCD_Device;
+}
+
+int viafb_input_parameter_converter(int parameter_value)
+{
+ int result;
+
+ if (parameter_value >= 1 && parameter_value <= 9)
+ result = 1 << (parameter_value - 1);
+ else
+ result = 1;
+
+ return result;
+}
diff --git a/drivers/video/via/via_utility.h b/drivers/video/via/via_utility.h
new file mode 100644
index 00000000000..2fd455202eb
--- /dev/null
+++ b/drivers/video/via/via_utility.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __VIAUTILITY_H__
+#define __VIAUTILITY_H__
+
+/* These functions are used to get infomation about device's state */
+void viafb_get_device_support_state(u32 *support_state);
+void viafb_get_device_connect_state(u32 *connect_state);
+bool viafb_lcd_get_support_expand_state(u32 xres, u32 yres);
+
+/* These function are used to access gamma table */
+void viafb_set_gamma_table(int bpp, unsigned int *gamma_table);
+void viafb_get_gamma_table(unsigned int *gamma_table);
+void viafb_get_gamma_support_state(int bpp, unsigned int *support_state);
+int viafb_input_parameter_converter(int parameter_value);
+
+#endif /* __VIAUTILITY_H__ */
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
new file mode 100644
index 00000000000..0132eae06f5
--- /dev/null
+++ b/drivers/video/via/viafbdev.c
@@ -0,0 +1,2571 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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>
+#define _MASTER_FILE
+
+#include "global.h"
+
+static int MAX_CURS = 32;
+static struct fb_var_screeninfo default_var;
+static char *viafb_name = "Via";
+static u32 pseudo_pal[17];
+
+/* video mode */
+static char *viafb_mode = "640x480";
+static char *viafb_mode1 = "640x480";
+static int viafb_resMode = VIA_RES_640X480;
+
+/* Added for specifying active devices.*/
+char *viafb_active_dev = "";
+
+/* Added for specifying video on devices.*/
+char *viafb_video_dev = "";
+
+/*Added for specify lcd output port*/
+char *viafb_lcd_port = "";
+char *viafb_dvi_port = "";
+
+static void viafb_set_device(struct device_t active_dev);
+static int apply_device_setting(struct viafb_ioctl_setting setting_info,
+ struct fb_info *info);
+static void apply_second_mode_setting(struct fb_var_screeninfo
+ *sec_var);
+static void retrieve_device_setting(struct viafb_ioctl_setting
+ *setting_info);
+static void viafb_set_video_device(u32 video_dev_info);
+static void viafb_get_video_device(u32 *video_dev_info);
+
+/* Mode information */
+static const struct viafb_modeinfo viafb_modentry[] = {
+ {480, 640, VIA_RES_480X640, "480x640"},
+ {640, 480, VIA_RES_640X480, "640x480"},
+ {800, 480, VIA_RES_800X480, "800x480"},
+ {800, 600, VIA_RES_800X600, "800x600"},
+ {1024, 768, VIA_RES_1024X768, "1024x768"},
+ {1152, 864, VIA_RES_1152X864, "1152x864"},
+ {1280, 1024, VIA_RES_1280X1024, "1280x1024"},
+ {1600, 1200, VIA_RES_1600X1200, "1600x1200"},
+ {1440, 1050, VIA_RES_1440X1050, "1440x1050"},
+ {1280, 768, VIA_RES_1280X768, "1280x768"},
+ {1280, 800, VIA_RES_1280X800, "1280x800"},
+ {1280, 960, VIA_RES_1280X960, "1280x960"},
+ {1920, 1440, VIA_RES_1920X1440, "1920x1440"},
+ {848, 480, VIA_RES_848X480, "848x480"},
+ {1400, 1050, VIA_RES_1400X1050, "1400x1050"},
+ {720, 480, VIA_RES_720X480, "720x480"},
+ {720, 576, VIA_RES_720X576, "720x576"},
+ {1024, 512, VIA_RES_1024X512, "1024x512"},
+ {1024, 576, VIA_RES_1024X576, "1024x576"},
+ {1024, 600, VIA_RES_1024X600, "1024x600"},
+ {1280, 720, VIA_RES_1280X720, "1280x720"},
+ {1920, 1080, VIA_RES_1920X1080, "1920x1080"},
+ {1366, 768, VIA_RES_1368X768, "1368x768"},
+ {1680, 1050, VIA_RES_1680X1050, "1680x1050"},
+ {960, 600, VIA_RES_960X600, "960x600"},
+ {1000, 600, VIA_RES_1000X600, "1000x600"},
+ {1024, 576, VIA_RES_1024X576, "1024x576"},
+ {1024, 600, VIA_RES_1024X600, "1024x600"},
+ {1088, 612, VIA_RES_1088X612, "1088x612"},
+ {1152, 720, VIA_RES_1152X720, "1152x720"},
+ {1200, 720, VIA_RES_1200X720, "1200x720"},
+ {1280, 600, VIA_RES_1280X600, "1280x600"},
+ {1360, 768, VIA_RES_1360X768, "1360x768"},
+ {1440, 900, VIA_RES_1440X900, "1440x900"},
+ {1600, 900, VIA_RES_1600X900, "1600x900"},
+ {1600, 1024, VIA_RES_1600X1024, "1600x1024"},
+ {1792, 1344, VIA_RES_1792X1344, "1792x1344"},
+ {1856, 1392, VIA_RES_1856X1392, "1856x1392"},
+ {1920, 1200, VIA_RES_1920X1200, "1920x1200"},
+ {2048, 1536, VIA_RES_2048X1536, "2048x1536"},
+ {0, 0, VIA_RES_INVALID, "640x480"}
+};
+
+static struct fb_ops viafb_ops;
+
+static int viafb_update_fix(struct fb_fix_screeninfo *fix, struct fb_info *info)
+{
+ struct viafb_par *ppar;
+ ppar = info->par;
+
+ DEBUG_MSG(KERN_INFO "viafb_update_fix!\n");
+
+ fix->visual =
+ ppar->bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
+ fix->line_length = ppar->linelength;
+
+ return 0;
+}
+
+
+static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
+ struct viafb_par *viaparinfo)
+{
+ memset(fix, 0, sizeof(struct fb_fix_screeninfo));
+ strcpy(fix->id, viafb_name);
+
+ fix->smem_start = viaparinfo->fbmem;
+ fix->smem_len = viaparinfo->fbmem_free;
+ fix->mmio_start = viaparinfo->mmio_base;
+ fix->mmio_len = viaparinfo->mmio_len;
+
+ fix->type = FB_TYPE_PACKED_PIXELS;
+ fix->type_aux = 0;
+
+ fix->xpanstep = fix->ywrapstep = 0;
+ fix->ypanstep = 1;
+
+ /* Just tell the accel name */
+ viafbinfo->fix.accel = FB_ACCEL_VIA_UNICHROME;
+}
+static int viafb_open(struct fb_info *info, int user)
+{
+ DEBUG_MSG(KERN_INFO "viafb_open!\n");
+ return 0;
+}
+
+static int viafb_release(struct fb_info *info, int user)
+{
+ DEBUG_MSG(KERN_INFO "viafb_release!\n");
+ return 0;
+}
+
+static void viafb_update_viafb_par(struct fb_info *info)
+{
+ struct viafb_par *ppar;
+
+ ppar = info->par;
+ ppar->bpp = info->var.bits_per_pixel;
+ ppar->linelength = ((info->var.xres_virtual + 7) & ~7) * ppar->bpp / 8;
+ ppar->hres = info->var.xres;
+ ppar->vres = info->var.yres;
+ ppar->xoffset = info->var.xoffset;
+ ppar->yoffset = info->var.yoffset;
+}
+
+static int viafb_check_var(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ int vmode_index, htotal, vtotal;
+ struct viafb_par *ppar;
+ u32 long_refresh;
+ struct viafb_par *p_viafb_par;
+ ppar = info->par;
+
+
+ DEBUG_MSG(KERN_INFO "viafb_check_var!\n");
+ /* Sanity check */
+ /* HW neither support interlacte nor double-scaned mode */
+ if (var->vmode & FB_VMODE_INTERLACED || var->vmode & FB_VMODE_DOUBLE)
+ return -EINVAL;
+
+ vmode_index = viafb_get_mode_index(var->xres, var->yres, 0);
+ if (vmode_index == VIA_RES_INVALID) {
+ DEBUG_MSG(KERN_INFO
+ "viafb: Mode %dx%dx%d not supported!!\n",
+ var->xres, var->yres, var->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ if (24 == var->bits_per_pixel)
+ var->bits_per_pixel = 32;
+
+ if (var->bits_per_pixel != 8 && var->bits_per_pixel != 16 &&
+ var->bits_per_pixel != 32)
+ return -EINVAL;
+
+ if ((var->xres_virtual * (var->bits_per_pixel >> 3)) & 0x1F)
+ /*32 pixel alignment */
+ var->xres_virtual = (var->xres_virtual + 31) & ~31;
+ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 >
+ ppar->memsize)
+ return -EINVAL;
+
+ /* Based on var passed in to calculate the refresh,
+ * because our driver use some modes special.
+ */
+ htotal = var->xres + var->left_margin +
+ var->right_margin + var->hsync_len;
+ vtotal = var->yres + var->upper_margin +
+ var->lower_margin + var->vsync_len;
+ long_refresh = 1000000000UL / var->pixclock * 1000;
+ long_refresh /= (htotal * vtotal);
+
+ viafb_refresh = viafb_get_refresh(var->xres, var->yres, long_refresh);
+
+ /* Adjust var according to our driver's own table */
+ viafb_fill_var_timing_info(var, viafb_refresh, vmode_index);
+
+ /* This is indeed a patch for VT3353 */
+ if (!info->par)
+ return -1;
+ p_viafb_par = (struct viafb_par *)info->par;
+ if (p_viafb_par->chip_info->gfx_chip_name == UNICHROME_VX800)
+ var->accel_flags = 0;
+
+ return 0;
+}
+
+static int viafb_set_par(struct fb_info *info)
+{
+ int vmode_index;
+ int vmode_index1 = 0;
+ DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
+
+ viafb_update_device_setting(info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, viafb_refresh, 0);
+
+ vmode_index = viafb_get_mode_index(info->var.xres, info->var.yres, 0);
+
+ if (viafb_SAMM_ON == 1) {
+ DEBUG_MSG(KERN_INFO
+ "viafb_second_xres = %d, viafb_second_yres = %d, bpp = %d\n",
+ viafb_second_xres, viafb_second_yres, viafb_bpp1);
+ vmode_index1 = viafb_get_mode_index(viafb_second_xres,
+ viafb_second_yres, 1);
+ DEBUG_MSG(KERN_INFO "->viafb_SAMM_ON: index=%d\n",
+ vmode_index1);
+
+ viafb_update_device_setting(viafb_second_xres,
+ viafb_second_yres, viafb_bpp1, viafb_refresh1, 1);
+ }
+
+ if (vmode_index != VIA_RES_INVALID) {
+ viafb_setmode(vmode_index, info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, vmode_index1,
+ viafb_second_xres, viafb_second_yres, viafb_bpp1);
+
+ /*We should set memory offset according virtual_x */
+ /*Fix me:put this function into viafb_setmode */
+ viafb_memory_pitch_patch(info);
+
+ /* Update ***fb_par information */
+ viafb_update_viafb_par(info);
+
+ /* Update other fixed information */
+ viafb_update_fix(&info->fix, info);
+ viafb_bpp = info->var.bits_per_pixel;
+ /* Update viafb_accel, it is necessary to our 2D accelerate */
+ viafb_accel = info->var.accel_flags;
+
+ if (viafb_accel)
+ viafb_set_2d_color_depth(info->var.bits_per_pixel);
+ }
+
+ return 0;
+}
+
+/* Set one color register */
+static int viafb_setcolreg(unsigned regno, unsigned red, unsigned green,
+unsigned blue, unsigned transp, struct fb_info *info)
+{
+ u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
+ unsigned cmap_entries = (info->var.bits_per_pixel == 8) ? 256 : 16;
+ DEBUG_MSG(KERN_INFO "viafb_setcolreg!\n");
+ if (regno >= cmap_entries)
+ return 1;
+ if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
+ /*
+ * Read PCI bus 0,dev 0,function 0,index 0xF6 to get chip rev.
+ */
+ outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
+ rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
+ }
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ outb(0x1A, 0x3C4);
+ sr1a = inb(0x3C5);
+ outb(0x1B, 0x3C4);
+ sr1b = inb(0x3C5);
+ outb(0x67, 0x3D4);
+ cr67 = inb(0x3D5);
+ outb(0x6A, 0x3D4);
+ cr6a = inb(0x3D5);
+
+ /* Map the 3C6/7/8/9 to the IGA2 */
+ outb(0x1A, 0x3C4);
+ outb(sr1a | 0x01, 0x3C5);
+ /* Second Display Engine colck always on */
+ outb(0x1B, 0x3C4);
+ outb(sr1b | 0x80, 0x3C5);
+ /* Second Display Color Depth 8 */
+ outb(0x67, 0x3D4);
+ outb(cr67 & 0x3F, 0x3D5);
+ outb(0x6A, 0x3D4);
+ /* Second Display Channel Reset CR6A[6]) */
+ outb(cr6a & 0xBF, 0x3D5);
+ /* Second Display Channel Enable CR6A[7] */
+ outb(cr6a | 0x80, 0x3D5);
+ /* Second Display Channel stop reset) */
+ outb(cr6a | 0x40, 0x3D5);
+
+ /* Bit mask of palette */
+ outb(0xFF, 0x3c6);
+ /* Write one register of IGA2 */
+ outb(regno, 0x3C8);
+ if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
+ rev >= 15) {
+ shift = 8;
+ viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
+ viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
+ } else {
+ shift = 10;
+ viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
+ viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
+ }
+ outb(red >> shift, 0x3C9);
+ outb(green >> shift, 0x3C9);
+ outb(blue >> shift, 0x3C9);
+
+ /* Map the 3C6/7/8/9 to the IGA1 */
+ outb(0x1A, 0x3C4);
+ outb(sr1a & 0xFE, 0x3C5);
+ /* Bit mask of palette */
+ outb(0xFF, 0x3c6);
+ /* Write one register of IGA1 */
+ outb(regno, 0x3C8);
+ outb(red >> shift, 0x3C9);
+ outb(green >> shift, 0x3C9);
+ outb(blue >> shift, 0x3C9);
+
+ outb(0x1A, 0x3C4);
+ outb(sr1a, 0x3C5);
+ outb(0x1B, 0x3C4);
+ outb(sr1b, 0x3C5);
+ outb(0x67, 0x3D4);
+ outb(cr67, 0x3D5);
+ outb(0x6A, 0x3D4);
+ outb(cr6a, 0x3D5);
+ break;
+ case 16:
+ ((u32 *) info->pseudo_palette)[regno] = (red & 0xF800) |
+ ((green & 0xFC00) >> 5) | ((blue & 0xF800) >> 11);
+ break;
+ case 32:
+ ((u32 *) info->pseudo_palette)[regno] =
+ ((transp & 0xFF00) << 16) |
+ ((red & 0xFF00) << 8) |
+ ((green & 0xFF00)) | ((blue & 0xFF00) >> 8);
+ break;
+ }
+
+ return 0;
+
+}
+
+/*CALLED BY: fb_set_cmap */
+/* fb_set_var, pass 256 colors */
+/*CALLED BY: fb_set_cmap */
+/* fbcon_set_palette, pass 16 colors */
+static int viafb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ u32 len = cmap->len;
+ u32 i;
+ u16 *pred = cmap->red;
+ u16 *pgreen = cmap->green;
+ u16 *pblue = cmap->blue;
+ u16 *ptransp = cmap->transp;
+ u8 sr1a, sr1b, cr67, cr6a, rev = 0, shift = 10;
+ if (len > 256)
+ return 1;
+ if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name) {
+ /*
+ * Read PCI bus 0, dev 0, function 0, index 0xF6 to get chip
+ * rev.
+ */
+ outl(0x80000000 | (0xf6 & ~3), (unsigned long)0xCF8);
+ rev = (inl((unsigned long)0xCFC) >> ((0xf6 & 3) * 8)) & 0xff;
+ }
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ outb(0x1A, 0x3C4);
+ sr1a = inb(0x3C5);
+ outb(0x1B, 0x3C4);
+ sr1b = inb(0x3C5);
+ outb(0x67, 0x3D4);
+ cr67 = inb(0x3D5);
+ outb(0x6A, 0x3D4);
+ cr6a = inb(0x3D5);
+ /* Map the 3C6/7/8/9 to the IGA2 */
+ outb(0x1A, 0x3C4);
+ outb(sr1a | 0x01, 0x3C5);
+ outb(0x1B, 0x3C4);
+ /* Second Display Engine colck always on */
+ outb(sr1b | 0x80, 0x3C5);
+ outb(0x67, 0x3D4);
+ /* Second Display Color Depth 8 */
+ outb(cr67 & 0x3F, 0x3D5);
+ outb(0x6A, 0x3D4);
+ /* Second Display Channel Reset CR6A[6]) */
+ outb(cr6a & 0xBF, 0x3D5);
+ /* Second Display Channel Enable CR6A[7] */
+ outb(cr6a | 0x80, 0x3D5);
+ /* Second Display Channel stop reset) */
+ outb(cr6a | 0xC0, 0x3D5);
+
+ /* Bit mask of palette */
+ outb(0xFF, 0x3c6);
+ outb(0x00, 0x3C8);
+ if (UNICHROME_CLE266 == viaparinfo->chip_info->gfx_chip_name &&
+ rev >= 15) {
+ shift = 8;
+ viafb_write_reg_mask(CR6A, VIACR, BIT5, BIT5);
+ viafb_write_reg_mask(SR15, VIASR, BIT7, BIT7);
+ } else {
+ shift = 10;
+ viafb_write_reg_mask(CR6A, VIACR, 0, BIT5);
+ viafb_write_reg_mask(SR15, VIASR, 0, BIT7);
+ }
+ for (i = 0; i < len; i++) {
+ outb((*(pred + i)) >> shift, 0x3C9);
+ outb((*(pgreen + i)) >> shift, 0x3C9);
+ outb((*(pblue + i)) >> shift, 0x3C9);
+ }
+
+ outb(0x1A, 0x3C4);
+ /* Map the 3C6/7/8/9 to the IGA1 */
+ outb(sr1a & 0xFE, 0x3C5);
+ /* Bit mask of palette */
+ outb(0xFF, 0x3c6);
+ outb(0x00, 0x3C8);
+ for (i = 0; i < len; i++) {
+ outb((*(pred + i)) >> shift, 0x3C9);
+ outb((*(pgreen + i)) >> shift, 0x3C9);
+ outb((*(pblue + i)) >> shift, 0x3C9);
+ }
+
+ outb(0x1A, 0x3C4);
+ outb(sr1a, 0x3C5);
+ outb(0x1B, 0x3C4);
+ outb(sr1b, 0x3C5);
+ outb(0x67, 0x3D4);
+ outb(cr67, 0x3D5);
+ outb(0x6A, 0x3D4);
+ outb(cr6a, 0x3D5);
+ break;
+ case 16:
+ if (len > 17)
+ return 0; /* Because static u32 pseudo_pal[17]; */
+ for (i = 0; i < len; i++)
+ ((u32 *) info->pseudo_palette)[i] =
+ (*(pred + i) & 0xF800) |
+ ((*(pgreen + i) & 0xFC00) >> 5) |
+ ((*(pblue + i) & 0xF800) >> 11);
+ break;
+ case 32:
+ if (len > 17)
+ return 0;
+ if (ptransp) {
+ for (i = 0; i < len; i++)
+ ((u32 *) info->pseudo_palette)[i] =
+ ((*(ptransp + i) & 0xFF00) << 16) |
+ ((*(pred + i) & 0xFF00) << 8) |
+ ((*(pgreen + i) & 0xFF00)) |
+ ((*(pblue + i) & 0xFF00) >> 8);
+ } else {
+ for (i = 0; i < len; i++)
+ ((u32 *) info->pseudo_palette)[i] =
+ 0x00000000 |
+ ((*(pred + i) & 0xFF00) << 8) |
+ ((*(pgreen + i) & 0xFF00)) |
+ ((*(pblue + i) & 0xFF00) >> 8);
+ }
+ break;
+ }
+ return 0;
+}
+
+static int viafb_pan_display(struct fb_var_screeninfo *var,
+ struct fb_info *info)
+{
+ unsigned int offset;
+
+ DEBUG_MSG(KERN_INFO "viafb_pan_display!\n");
+
+ offset = (var->xoffset + (var->yoffset * var->xres_virtual)) *
+ var->bits_per_pixel / 16;
+
+ DEBUG_MSG(KERN_INFO "\nviafb_pan_display,offset =%d ", offset);
+
+ viafb_write_reg_mask(0x48, 0x3d4, ((offset >> 24) & 0x3), 0x3);
+ viafb_write_reg_mask(0x34, 0x3d4, ((offset >> 16) & 0xff), 0xff);
+ viafb_write_reg_mask(0x0c, 0x3d4, ((offset >> 8) & 0xff), 0xff);
+ viafb_write_reg_mask(0x0d, 0x3d4, (offset & 0xff), 0xff);
+
+ return 0;
+}
+
+static int viafb_blank(int blank_mode, struct fb_info *info)
+{
+ DEBUG_MSG(KERN_INFO "viafb_blank!\n");
+ /* clear DPMS setting */
+
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ /* Screen: On, HSync: On, VSync: On */
+ /* control CRT monitor power management */
+ viafb_write_reg_mask(CR36, VIACR, 0x00, BIT4 + BIT5);
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* Screen: Off, HSync: Off, VSync: On */
+ /* control CRT monitor power management */
+ viafb_write_reg_mask(CR36, VIACR, 0x10, BIT4 + BIT5);
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ /* Screen: Off, HSync: On, VSync: Off */
+ /* control CRT monitor power management */
+ viafb_write_reg_mask(CR36, VIACR, 0x20, BIT4 + BIT5);
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* Screen: Off, HSync: Off, VSync: Off */
+ /* control CRT monitor power management */
+ viafb_write_reg_mask(CR36, VIACR, 0x30, BIT4 + BIT5);
+ break;
+ }
+
+ return 0;
+}
+
+static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
+{
+ struct viafb_ioctl_mode viamode;
+ struct viafb_ioctl_samm viasamm;
+ struct viafb_driver_version driver_version;
+ struct fb_var_screeninfo sec_var;
+ struct _panel_size_pos_info panel_pos_size_para;
+ u32 state_info = 0;
+ u32 viainfo_size = sizeof(struct viafb_ioctl_info);
+ u32 *viafb_gamma_table;
+ char driver_name[] = "viafb";
+
+ u32 __user *argp = (u32 __user *) arg;
+ u32 gpu32;
+ u32 video_dev_info = 0;
+ struct viafb_ioctl_setting viafb_setting = {};
+ struct device_t active_dev = {};
+
+ DEBUG_MSG(KERN_INFO "viafb_ioctl: 0x%X !!\n", cmd);
+
+ switch (cmd) {
+ case VIAFB_GET_CHIP_INFO:
+ if (copy_to_user(argp, viaparinfo->chip_info,
+ sizeof(struct chip_information)))
+ return -EFAULT;
+ break;
+ case VIAFB_GET_INFO_SIZE:
+ return put_user(viainfo_size, argp);
+ case VIAFB_GET_INFO:
+ return viafb_ioctl_get_viafb_info(arg);
+ case VIAFB_HOTPLUG:
+ return put_user(viafb_ioctl_hotplug(info->var.xres,
+ info->var.yres,
+ info->var.bits_per_pixel), argp);
+ case VIAFB_SET_HOTPLUG_FLAG:
+ if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+ return -EFAULT;
+ viafb_hotplug = (gpu32) ? 1 : 0;
+ break;
+ case VIAFB_GET_RESOLUTION:
+ viamode.xres = (u32) viafb_hotplug_Xres;
+ viamode.yres = (u32) viafb_hotplug_Yres;
+ viamode.refresh = (u32) viafb_hotplug_refresh;
+ viamode.bpp = (u32) viafb_hotplug_bpp;
+ if (viafb_SAMM_ON == 1) {
+ viamode.xres_sec = viafb_second_xres;
+ viamode.yres_sec = viafb_second_yres;
+ viamode.virtual_xres_sec = viafb_second_virtual_xres;
+ viamode.virtual_yres_sec = viafb_second_virtual_yres;
+ viamode.refresh_sec = viafb_refresh1;
+ viamode.bpp_sec = viafb_bpp1;
+ } else {
+ viamode.xres_sec = 0;
+ viamode.yres_sec = 0;
+ viamode.virtual_xres_sec = 0;
+ viamode.virtual_yres_sec = 0;
+ viamode.refresh_sec = 0;
+ viamode.bpp_sec = 0;
+ }
+ if (copy_to_user(argp, &viamode, sizeof(viamode)))
+ return -EFAULT;
+ break;
+ case VIAFB_GET_SAMM_INFO:
+ viasamm.samm_status = viafb_SAMM_ON;
+
+ if (viafb_SAMM_ON == 1) {
+ if (viafb_dual_fb) {
+ viasamm.size_prim = viaparinfo->fbmem_free;
+ viasamm.size_sec = viaparinfo1->fbmem_free;
+ } else {
+ if (viafb_second_size) {
+ viasamm.size_prim =
+ viaparinfo->fbmem_free -
+ viafb_second_size * 1024 * 1024;
+ viasamm.size_sec =
+ viafb_second_size * 1024 * 1024;
+ } else {
+ viasamm.size_prim =
+ viaparinfo->fbmem_free >> 1;
+ viasamm.size_sec =
+ (viaparinfo->fbmem_free >> 1);
+ }
+ }
+ viasamm.mem_base = viaparinfo->fbmem;
+ viasamm.offset_sec = viafb_second_offset;
+ } else {
+ viasamm.size_prim =
+ viaparinfo->memsize - viaparinfo->fbmem_used;
+ viasamm.size_sec = 0;
+ viasamm.mem_base = viaparinfo->fbmem;
+ viasamm.offset_sec = 0;
+ }
+
+ if (copy_to_user(argp, &viasamm, sizeof(viasamm)))
+ return -EFAULT;
+
+ break;
+ case VIAFB_TURN_ON_OUTPUT_DEVICE:
+ if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+ return -EFAULT;
+ if (gpu32 & CRT_Device)
+ viafb_crt_enable();
+ if (gpu32 & DVI_Device)
+ viafb_dvi_enable();
+ if (gpu32 & LCD_Device)
+ viafb_lcd_enable();
+ break;
+ case VIAFB_TURN_OFF_OUTPUT_DEVICE:
+ if (copy_from_user(&gpu32, argp, sizeof(gpu32)))
+ return -EFAULT;
+ if (gpu32 & CRT_Device)
+ viafb_crt_disable();
+ if (gpu32 & DVI_Device)
+ viafb_dvi_disable();
+ if (gpu32 & LCD_Device)
+ viafb_lcd_disable();
+ break;
+ case VIAFB_SET_DEVICE:
+ if (copy_from_user(&active_dev, (void *)argp,
+ sizeof(active_dev)))
+ return -EFAULT;
+ viafb_set_device(active_dev);
+ viafb_set_par(info);
+ break;
+ case VIAFB_GET_DEVICE:
+ active_dev.crt = viafb_CRT_ON;
+ active_dev.dvi = viafb_DVI_ON;
+ active_dev.lcd = viafb_LCD_ON;
+ active_dev.samm = viafb_SAMM_ON;
+ active_dev.primary_dev = viafb_primary_dev;
+
+ active_dev.lcd_dsp_cent = viafb_lcd_dsp_method;
+ active_dev.lcd_panel_id = viafb_lcd_panel_id;
+ active_dev.lcd_mode = viafb_lcd_mode;
+
+ active_dev.xres = viafb_hotplug_Xres;
+ active_dev.yres = viafb_hotplug_Yres;
+
+ active_dev.xres1 = viafb_second_xres;
+ active_dev.yres1 = viafb_second_yres;
+
+ active_dev.bpp = viafb_bpp;
+ active_dev.bpp1 = viafb_bpp1;
+ active_dev.refresh = viafb_refresh;
+ active_dev.refresh1 = viafb_refresh1;
+
+ active_dev.epia_dvi = viafb_platform_epia_dvi;
+ active_dev.lcd_dual_edge = viafb_device_lcd_dualedge;
+ active_dev.bus_width = viafb_bus_width;
+
+ if (copy_to_user(argp, &active_dev, sizeof(active_dev)))
+ return -EFAULT;
+ break;
+
+ case VIAFB_GET_DRIVER_VERSION:
+ driver_version.iMajorNum = VERSION_MAJOR;
+ driver_version.iKernelNum = VERSION_KERNEL;
+ driver_version.iOSNum = VERSION_OS;
+ driver_version.iMinorNum = VERSION_MINOR;
+
+ if (copy_to_user(argp, &driver_version,
+ sizeof(driver_version)))
+ return -EFAULT;
+
+ break;
+
+ case VIAFB_SET_DEVICE_INFO:
+ if (copy_from_user(&viafb_setting,
+ argp, sizeof(viafb_setting)))
+ return -EFAULT;
+ if (apply_device_setting(viafb_setting, info) < 0)
+ return -EINVAL;
+
+ break;
+
+ case VIAFB_SET_SECOND_MODE:
+ if (copy_from_user(&sec_var, argp, sizeof(sec_var)))
+ return -EFAULT;
+ apply_second_mode_setting(&sec_var);
+ break;
+
+ case VIAFB_GET_DEVICE_INFO:
+
+ retrieve_device_setting(&viafb_setting);
+
+ if (copy_to_user(argp, &viafb_setting, sizeof(viafb_setting)))
+ return -EFAULT;
+
+ break;
+
+ case VIAFB_GET_DEVICE_SUPPORT:
+ viafb_get_device_support_state(&state_info);
+ if (put_user(state_info, argp))
+ return -EFAULT;
+ break;
+
+ case VIAFB_GET_DEVICE_CONNECT:
+ viafb_get_device_connect_state(&state_info);
+ if (put_user(state_info, argp))
+ return -EFAULT;
+ break;
+
+ case VIAFB_GET_PANEL_SUPPORT_EXPAND:
+ state_info =
+ viafb_lcd_get_support_expand_state(info->var.xres,
+ info->var.yres);
+ if (put_user(state_info, argp))
+ return -EFAULT;
+ break;
+
+ case VIAFB_GET_DRIVER_NAME:
+ if (copy_to_user(argp, driver_name, sizeof(driver_name)))
+ return -EFAULT;
+ break;
+
+ case VIAFB_SET_GAMMA_LUT:
+ viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
+ if (!viafb_gamma_table)
+ return -ENOMEM;
+ if (copy_from_user(viafb_gamma_table, argp,
+ sizeof(viafb_gamma_table))) {
+ kfree(viafb_gamma_table);
+ return -EFAULT;
+ }
+ viafb_set_gamma_table(viafb_bpp, viafb_gamma_table);
+ kfree(viafb_gamma_table);
+ break;
+
+ case VIAFB_GET_GAMMA_LUT:
+ viafb_gamma_table = kmalloc(256 * sizeof(u32), GFP_KERNEL);
+ if (!viafb_gamma_table)
+ return -ENOMEM;
+ viafb_get_gamma_table(viafb_gamma_table);
+ if (copy_to_user(argp, viafb_gamma_table,
+ sizeof(viafb_gamma_table))) {
+ kfree(viafb_gamma_table);
+ return -EFAULT;
+ }
+ kfree(viafb_gamma_table);
+ break;
+
+ case VIAFB_GET_GAMMA_SUPPORT_STATE:
+ viafb_get_gamma_support_state(viafb_bpp, &state_info);
+ if (put_user(state_info, argp))
+ return -EFAULT;
+ break;
+ case VIAFB_SET_VIDEO_DEVICE:
+ get_user(video_dev_info, argp);
+ viafb_set_video_device(video_dev_info);
+ break;
+ case VIAFB_GET_VIDEO_DEVICE:
+ viafb_get_video_device(&video_dev_info);
+ if (put_user(video_dev_info, argp))
+ return -EFAULT;
+ break;
+ case VIAFB_SYNC_SURFACE:
+ DEBUG_MSG(KERN_INFO "lobo VIAFB_SYNC_SURFACE\n");
+ break;
+ case VIAFB_GET_DRIVER_CAPS:
+ break;
+
+ case VIAFB_GET_PANEL_MAX_SIZE:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ panel_pos_size_para.x = panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &panel_pos_size_para,
+ sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+ case VIAFB_GET_PANEL_MAX_POSITION:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ panel_pos_size_para.x = panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &panel_pos_size_para,
+ sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+
+ case VIAFB_GET_PANEL_POSITION:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ panel_pos_size_para.x = panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &panel_pos_size_para,
+ sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+ case VIAFB_GET_PANEL_SIZE:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ panel_pos_size_para.x = panel_pos_size_para.y = 0;
+ if (copy_to_user(argp, &panel_pos_size_para,
+ sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+
+ case VIAFB_SET_PANEL_POSITION:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+ case VIAFB_SET_PANEL_SIZE:
+ if (copy_from_user
+ (&panel_pos_size_para, argp, sizeof(panel_pos_size_para)))
+ return -EFAULT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void viafb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ u32 col = 0, rop = 0;
+ int pitch;
+
+ if (!viafb_accel)
+ return cfb_fillrect(info, rect);
+
+ if (!rect->width || !rect->height)
+ return;
+
+ switch (rect->rop) {
+ case ROP_XOR:
+ rop = 0x5A;
+ break;
+ case ROP_COPY:
+ default:
+ rop = 0xF0;
+ break;
+ }
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ col = rect->color;
+ break;
+ case 16:
+ col = ((u32 *) (info->pseudo_palette))[rect->color];
+ break;
+ case 32:
+ col = ((u32 *) (info->pseudo_palette))[rect->color];
+ break;
+ }
+
+ /* BitBlt Source Address */
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+ /* Source Base Address */
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+ /* Destination Base Address */
+ writel(((unsigned long) (info->screen_base) -
+ (unsigned long) viafb_FB_MM) >> 3,
+ viaparinfo->io_virt + VIA_REG_DSTBASE);
+ /* Pitch */
+ pitch = (info->var.xres_virtual + 7) & ~7;
+ writel(VIA_PITCH_ENABLE |
+ (((pitch *
+ info->var.bits_per_pixel >> 3) >> 3) |
+ (((pitch * info->
+ var.bits_per_pixel >> 3) >> 3) << 16)),
+ viaparinfo->io_virt + VIA_REG_PITCH);
+ /* BitBlt Destination Address */
+ writel(((rect->dy << 16) | rect->dx),
+ viaparinfo->io_virt + VIA_REG_DSTPOS);
+ /* Dimension: width & height */
+ writel((((rect->height - 1) << 16) | (rect->width - 1)),
+ viaparinfo->io_virt + VIA_REG_DIMENSION);
+ /* Forground color or Destination color */
+ writel(col, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+ /* GE Command */
+ writel((0x01 | 0x2000 | (rop << 24)),
+ viaparinfo->io_virt + VIA_REG_GECMD);
+
+}
+
+static void viafb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ u32 dy = area->dy, sy = area->sy, direction = 0x0;
+ u32 sx = area->sx, dx = area->dx, width = area->width;
+ int pitch;
+
+ DEBUG_MSG(KERN_INFO "viafb_copyarea!!\n");
+
+ if (!viafb_accel)
+ return cfb_copyarea(info, area);
+
+ if (!area->width || !area->height)
+ return;
+
+ if (sy < dy) {
+ dy += area->height - 1;
+ sy += area->height - 1;
+ direction |= 0x4000;
+ }
+
+ if (sx < dx) {
+ dx += width - 1;
+ sx += width - 1;
+ direction |= 0x8000;
+ }
+
+ /* Source Base Address */
+ writel(((unsigned long) (info->screen_base) -
+ (unsigned long) viafb_FB_MM) >> 3,
+ viaparinfo->io_virt + VIA_REG_SRCBASE);
+ /* Destination Base Address */
+ writel(((unsigned long) (info->screen_base) -
+ (unsigned long) viafb_FB_MM) >> 3,
+ viaparinfo->io_virt + VIA_REG_DSTBASE);
+ /* Pitch */
+ pitch = (info->var.xres_virtual + 7) & ~7;
+ /* VIA_PITCH_ENABLE can be omitted now. */
+ writel(VIA_PITCH_ENABLE |
+ (((pitch *
+ info->var.bits_per_pixel >> 3) >> 3) | (((pitch *
+ info->var.
+ bits_per_pixel
+ >> 3) >> 3)
+ << 16)),
+ viaparinfo->io_virt + VIA_REG_PITCH);
+ /* BitBlt Source Address */
+ writel(((sy << 16) | sx), viaparinfo->io_virt + VIA_REG_SRCPOS);
+ /* BitBlt Destination Address */
+ writel(((dy << 16) | dx), viaparinfo->io_virt + VIA_REG_DSTPOS);
+ /* Dimension: width & height */
+ writel((((area->height - 1) << 16) | (area->width - 1)),
+ viaparinfo->io_virt + VIA_REG_DIMENSION);
+ /* GE Command */
+ writel((0x01 | direction | (0xCC << 24)),
+ viaparinfo->io_virt + VIA_REG_GECMD);
+
+}
+
+static void viafb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ u32 size, bg_col = 0, fg_col = 0, *udata;
+ int i;
+ int pitch;
+
+ if (!viafb_accel)
+ return cfb_imageblit(info, image);
+
+ udata = (u32 *) image->data;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ bg_col = image->bg_color;
+ fg_col = image->fg_color;
+ break;
+ case 16:
+ bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color];
+ fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color];
+ break;
+ case 32:
+ bg_col = ((u32 *) (info->pseudo_palette))[image->bg_color];
+ fg_col = ((u32 *) (info->pseudo_palette))[image->fg_color];
+ break;
+ }
+ size = image->width * image->height;
+
+ /* Source Base Address */
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCBASE);
+ /* Destination Base Address */
+ writel(((unsigned long) (info->screen_base) -
+ (unsigned long) viafb_FB_MM) >> 3,
+ viaparinfo->io_virt + VIA_REG_DSTBASE);
+ /* Pitch */
+ pitch = (info->var.xres_virtual + 7) & ~7;
+ writel(VIA_PITCH_ENABLE |
+ (((pitch *
+ info->var.bits_per_pixel >> 3) >> 3) | (((pitch *
+ info->var.
+ bits_per_pixel
+ >> 3) >> 3)
+ << 16)),
+ viaparinfo->io_virt + VIA_REG_PITCH);
+ /* BitBlt Source Address */
+ writel(0x0, viaparinfo->io_virt + VIA_REG_SRCPOS);
+ /* BitBlt Destination Address */
+ writel(((image->dy << 16) | image->dx),
+ viaparinfo->io_virt + VIA_REG_DSTPOS);
+ /* Dimension: width & height */
+ writel((((image->height - 1) << 16) | (image->width - 1)),
+ viaparinfo->io_virt + VIA_REG_DIMENSION);
+ /* fb color */
+ writel(fg_col, viaparinfo->io_virt + VIA_REG_FGCOLOR);
+ /* bg color */
+ writel(bg_col, viaparinfo->io_virt + VIA_REG_BGCOLOR);
+ /* GE Command */
+ writel(0xCC020142, viaparinfo->io_virt + VIA_REG_GECMD);
+
+ for (i = 0; i < size / 4; i++) {
+ writel(*udata, viaparinfo->io_virt + VIA_MMIO_BLTBASE);
+ udata++;
+ }
+
+}
+
+static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ u8 data[CURSOR_SIZE / 8];
+ u32 data_bak[CURSOR_SIZE / 32];
+ u32 temp, xx, yy, bg_col = 0, fg_col = 0;
+ int size, i, j = 0;
+ static int hw_cursor;
+ struct viafb_par *p_viafb_par;
+
+ if (viafb_accel)
+ hw_cursor = 1;
+
+ if (!viafb_accel) {
+ if (hw_cursor) {
+ viafb_show_hw_cursor(info, HW_Cursor_OFF);
+ hw_cursor = 0;
+ }
+ return -ENODEV;
+ }
+
+ if ((((struct viafb_par *)(info->par))->iga_path == IGA2)
+ && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266))
+ return -ENODEV;
+
+ /* When duoview and using lcd , use soft cursor */
+ if (viafb_LCD_ON || ((struct viafb_par *)(info->par))->duoview)
+ return -ENODEV;
+
+ viafb_show_hw_cursor(info, HW_Cursor_OFF);
+ viacursor = *cursor;
+
+ if (cursor->set & FB_CUR_SETHOT) {
+ viacursor.hot = cursor->hot;
+ temp = ((viacursor.hot.x) << 16) + viacursor.hot.y;
+ writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_ORG);
+ }
+
+ if (cursor->set & FB_CUR_SETPOS) {
+ viacursor.image.dx = cursor->image.dx;
+ viacursor.image.dy = cursor->image.dy;
+ yy = cursor->image.dy - info->var.yoffset;
+ xx = cursor->image.dx - info->var.xoffset;
+ temp = yy & 0xFFFF;
+ temp |= (xx << 16);
+ writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_POS);
+ }
+
+ if (cursor->set & FB_CUR_SETSIZE) {
+ temp = readl(viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+
+ if ((cursor->image.width <= 32)
+ && (cursor->image.height <= 32)) {
+ MAX_CURS = 32;
+ temp |= 0x2;
+ } else if ((cursor->image.width <= 64)
+ && (cursor->image.height <= 64)) {
+ MAX_CURS = 64;
+ temp &= 0xFFFFFFFD;
+ } else {
+ DEBUG_MSG(KERN_INFO
+ "The cursor image is biger than 64x64 bits...\n");
+ return -ENXIO;
+ }
+ writel(temp, viaparinfo->io_virt + VIA_REG_CURSOR_MODE);
+
+ viacursor.image.height = cursor->image.height;
+ viacursor.image.width = cursor->image.width;
+ }
+
+ if (cursor->set & FB_CUR_SETCMAP) {
+ viacursor.image.fg_color = cursor->image.fg_color;
+ viacursor.image.bg_color = cursor->image.bg_color;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ case 16:
+ case 32:
+ bg_col =
+ (0xFF << 24) |
+ (((info->cmap.red)[viacursor.image.bg_color] &
+ 0xFF00) << 8) |
+ ((info->cmap.green)[viacursor.image.bg_color] &
+ 0xFF00) |
+ (((info->cmap.blue)[viacursor.image.bg_color] &
+ 0xFF00) >> 8);
+ fg_col =
+ (0xFF << 24) |
+ (((info->cmap.red)[viacursor.image.fg_color] &
+ 0xFF00) << 8) |
+ ((info->cmap.green)[viacursor.image.fg_color] &
+ 0xFF00) |
+ (((info->cmap.blue)[viacursor.image.fg_color] &
+ 0xFF00) >> 8);
+ break;
+ default:
+ return 0;
+ }
+
+ /* This is indeed a patch for VT3324/VT3353 */
+ if (!info->par)
+ return 0;
+ p_viafb_par = (struct viafb_par *)info->par;
+
+ if ((p_viafb_par->chip_info->gfx_chip_name ==
+ UNICHROME_CX700) ||
+ ((p_viafb_par->chip_info->gfx_chip_name ==
+ UNICHROME_VX800))) {
+ bg_col =
+ (((info->cmap.red)[viacursor.image.bg_color] &
+ 0xFFC0) << 14) |
+ (((info->cmap.green)[viacursor.image.bg_color] &
+ 0xFFC0) << 4) |
+ (((info->cmap.blue)[viacursor.image.bg_color] &
+ 0xFFC0) >> 6);
+ fg_col =
+ (((info->cmap.red)[viacursor.image.fg_color] &
+ 0xFFC0) << 14) |
+ (((info->cmap.green)[viacursor.image.fg_color] &
+ 0xFFC0) << 4) |
+ (((info->cmap.blue)[viacursor.image.fg_color] &
+ 0xFFC0) >> 6);
+ }
+
+ writel(bg_col, viaparinfo->io_virt + VIA_REG_CURSOR_BG);
+ writel(fg_col, viaparinfo->io_virt + VIA_REG_CURSOR_FG);
+ }
+
+ if (cursor->set & FB_CUR_SETSHAPE) {
+ size =
+ ((viacursor.image.width + 7) >> 3) *
+ viacursor.image.height;
+
+ if (MAX_CURS == 32) {
+ for (i = 0; i < (CURSOR_SIZE / 32); i++) {
+ data_bak[i] = 0x0;
+ data_bak[i + 1] = 0xFFFFFFFF;
+ i += 1;
+ }
+ } else if (MAX_CURS == 64) {
+ for (i = 0; i < (CURSOR_SIZE / 32); i++) {
+ data_bak[i] = 0x0;
+ data_bak[i + 1] = 0x0;
+ data_bak[i + 2] = 0xFFFFFFFF;
+ data_bak[i + 3] = 0xFFFFFFFF;
+ i += 3;
+ }
+ }
+
+ switch (viacursor.rop) {
+ case ROP_XOR:
+ for (i = 0; i < size; i++)
+ data[i] = viacursor.mask[i];
+ break;
+ case ROP_COPY:
+
+ for (i = 0; i < size; i++)
+ data[i] = viacursor.mask[i];
+ break;
+ default:
+ break;
+ }
+
+ if (MAX_CURS == 32) {
+ for (i = 0; i < size; i++) {
+ data_bak[j] = (u32) data[i];
+ data_bak[j + 1] = ~data_bak[j];
+ j += 2;
+ }
+ } else if (MAX_CURS == 64) {
+ for (i = 0; i < size; i++) {
+ data_bak[j] = (u32) data[i];
+ data_bak[j + 1] = 0x0;
+ data_bak[j + 2] = ~data_bak[j];
+ data_bak[j + 3] = ~data_bak[j + 1];
+ j += 4;
+ }
+ }
+
+ memcpy(((struct viafb_par *)(info->par))->fbmem_virt +
+ ((struct viafb_par *)(info->par))->cursor_start,
+ data_bak, CURSOR_SIZE);
+ }
+
+ if (viacursor.enable)
+ viafb_show_hw_cursor(info, HW_Cursor_ON);
+
+ return 0;
+}
+
+static int viafb_sync(struct fb_info *info)
+{
+ if (viafb_accel)
+ viafb_wait_engine_idle();
+ return 0;
+}
+
+int viafb_get_mode_index(int hres, int vres, int flag)
+{
+ u32 i;
+ DEBUG_MSG(KERN_INFO "viafb_get_mode_index!\n");
+
+ for (i = 0; viafb_modentry[i].mode_index != VIA_RES_INVALID; i++)
+ if (viafb_modentry[i].xres == hres &&
+ viafb_modentry[i].yres == vres)
+ break;
+
+ viafb_resMode = viafb_modentry[i].mode_index;
+ if (flag)
+ viafb_mode1 = viafb_modentry[i].mode_res;
+ else
+ viafb_mode = viafb_modentry[i].mode_res;
+
+ return viafb_resMode;
+}
+
+static void check_available_device_to_enable(int device_id)
+{
+ int device_num = 0;
+
+ /* Initialize: */
+ viafb_CRT_ON = STATE_OFF;
+ viafb_DVI_ON = STATE_OFF;
+ viafb_LCD_ON = STATE_OFF;
+ viafb_LCD2_ON = STATE_OFF;
+ viafb_DeviceStatus = None_Device;
+
+ if ((device_id & CRT_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+ viafb_CRT_ON = STATE_ON;
+ device_num++;
+ viafb_DeviceStatus |= CRT_Device;
+ }
+
+ if ((device_id & DVI_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+ viafb_DVI_ON = STATE_ON;
+ device_num++;
+ viafb_DeviceStatus |= DVI_Device;
+ }
+
+ if ((device_id & LCD_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+ viafb_LCD_ON = STATE_ON;
+ device_num++;
+ viafb_DeviceStatus |= LCD_Device;
+ }
+
+ if ((device_id & LCD2_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
+ viafb_LCD2_ON = STATE_ON;
+ device_num++;
+ viafb_DeviceStatus |= LCD2_Device;
+ }
+
+ if (viafb_DeviceStatus == None_Device) {
+ /* Use CRT as default active device: */
+ viafb_CRT_ON = STATE_ON;
+ viafb_DeviceStatus = CRT_Device;
+ }
+ DEBUG_MSG(KERN_INFO "Device Status:%x", viafb_DeviceStatus);
+}
+
+static void viafb_set_device(struct device_t active_dev)
+{
+ /* Check available device to enable: */
+ int device_id = None_Device;
+ if (active_dev.crt)
+ device_id |= CRT_Device;
+ if (active_dev.dvi)
+ device_id |= DVI_Device;
+ if (active_dev.lcd)
+ device_id |= LCD_Device;
+
+ check_available_device_to_enable(device_id);
+
+ /* Check property of LCD: */
+ if (viafb_LCD_ON) {
+ if (active_dev.lcd_dsp_cent) {
+ viaparinfo->lvds_setting_info->display_method =
+ viafb_lcd_dsp_method = LCD_CENTERING;
+ } else {
+ viaparinfo->lvds_setting_info->display_method =
+ viafb_lcd_dsp_method = LCD_EXPANDSION;
+ }
+
+ if (active_dev.lcd_mode == LCD_SPWG) {
+ viaparinfo->lvds_setting_info->lcd_mode =
+ viafb_lcd_mode = LCD_SPWG;
+ } else {
+ viaparinfo->lvds_setting_info->lcd_mode =
+ viafb_lcd_mode = LCD_OPENLDI;
+ }
+
+ if (active_dev.lcd_panel_id <= LCD_PANEL_ID_MAXIMUM) {
+ viafb_lcd_panel_id = active_dev.lcd_panel_id;
+ viafb_init_lcd_size();
+ }
+ }
+
+ /* Check property of mode: */
+ if (!active_dev.xres1)
+ viafb_second_xres = 640;
+ else
+ viafb_second_xres = active_dev.xres1;
+ if (!active_dev.yres1)
+ viafb_second_yres = 480;
+ else
+ viafb_second_yres = active_dev.yres1;
+ if (active_dev.bpp != 0)
+ viafb_bpp = active_dev.bpp;
+ if (active_dev.bpp1 != 0)
+ viafb_bpp1 = active_dev.bpp1;
+ if (active_dev.refresh != 0)
+ viafb_refresh = active_dev.refresh;
+ if (active_dev.refresh1 != 0)
+ viafb_refresh1 = active_dev.refresh1;
+ if ((active_dev.samm == STATE_OFF) || (active_dev.samm == STATE_ON))
+ viafb_SAMM_ON = active_dev.samm;
+ viafb_primary_dev = active_dev.primary_dev;
+
+ viafb_set_start_addr();
+ viafb_set_iga_path();
+}
+
+static void viafb_set_video_device(u32 video_dev_info)
+{
+ viaparinfo->video_on_crt = STATE_OFF;
+ viaparinfo->video_on_dvi = STATE_OFF;
+ viaparinfo->video_on_lcd = STATE_OFF;
+
+ /* Check available device to enable: */
+ if ((video_dev_info & CRT_Device) == CRT_Device)
+ viaparinfo->video_on_crt = STATE_ON;
+ else if ((video_dev_info & DVI_Device) == DVI_Device)
+ viaparinfo->video_on_dvi = STATE_ON;
+ else if ((video_dev_info & LCD_Device) == LCD_Device)
+ viaparinfo->video_on_lcd = STATE_ON;
+}
+
+static void viafb_get_video_device(u32 *video_dev_info)
+{
+ *video_dev_info = None_Device;
+ if (viaparinfo->video_on_crt == STATE_ON)
+ *video_dev_info |= CRT_Device;
+ else if (viaparinfo->video_on_dvi == STATE_ON)
+ *video_dev_info |= DVI_Device;
+ else if (viaparinfo->video_on_lcd == STATE_ON)
+ *video_dev_info |= LCD_Device;
+}
+
+static int get_primary_device(void)
+{
+ int primary_device = 0;
+ /* Rule: device on iga1 path are the primary device. */
+ if (viafb_SAMM_ON) {
+ if (viafb_CRT_ON) {
+ if (viaparinfo->crt_setting_info->iga_path == IGA1) {
+ DEBUG_MSG(KERN_INFO "CRT IGA Path:%d\n",
+ viaparinfo->
+ crt_setting_info->iga_path);
+ primary_device = CRT_Device;
+ }
+ }
+ if (viafb_DVI_ON) {
+ if (viaparinfo->tmds_setting_info->iga_path == IGA1) {
+ DEBUG_MSG(KERN_INFO "DVI IGA Path:%d\n",
+ viaparinfo->
+ tmds_setting_info->iga_path);
+ primary_device = DVI_Device;
+ }
+ }
+ if (viafb_LCD_ON) {
+ if (viaparinfo->lvds_setting_info->iga_path == IGA1) {
+ DEBUG_MSG(KERN_INFO "LCD IGA Path:%d\n",
+ viaparinfo->
+ lvds_setting_info->iga_path);
+ primary_device = LCD_Device;
+ }
+ }
+ if (viafb_LCD2_ON) {
+ if (viaparinfo->lvds_setting_info2->iga_path == IGA1) {
+ DEBUG_MSG(KERN_INFO "LCD2 IGA Path:%d\n",
+ viaparinfo->
+ lvds_setting_info2->iga_path);
+ primary_device = LCD2_Device;
+ }
+ }
+ }
+ return primary_device;
+}
+
+static u8 is_duoview(void)
+{
+ if (0 == viafb_SAMM_ON) {
+ if (viafb_LCD_ON + viafb_LCD2_ON +
+ viafb_DVI_ON + viafb_CRT_ON == 2)
+ return true;
+ return false;
+ } else {
+ return false;
+ }
+}
+
+static void apply_second_mode_setting(struct fb_var_screeninfo
+ *sec_var)
+{
+ u32 htotal, vtotal, long_refresh;
+
+ htotal = sec_var->xres + sec_var->left_margin +
+ sec_var->right_margin + sec_var->hsync_len;
+ vtotal = sec_var->yres + sec_var->upper_margin +
+ sec_var->lower_margin + sec_var->vsync_len;
+ if ((sec_var->xres_virtual * (sec_var->bits_per_pixel >> 3)) & 0x1F) {
+ /*Is 32 bytes alignment? */
+ /*32 pixel alignment */
+ sec_var->xres_virtual = (sec_var->xres_virtual + 31) & ~31;
+ }
+
+ htotal = sec_var->xres + sec_var->left_margin +
+ sec_var->right_margin + sec_var->hsync_len;
+ vtotal = sec_var->yres + sec_var->upper_margin +
+ sec_var->lower_margin + sec_var->vsync_len;
+ long_refresh = 1000000000UL / sec_var->pixclock * 1000;
+ long_refresh /= (htotal * vtotal);
+
+ viafb_second_xres = sec_var->xres;
+ viafb_second_yres = sec_var->yres;
+ viafb_second_virtual_xres = sec_var->xres_virtual;
+ viafb_second_virtual_yres = sec_var->yres_virtual;
+ viafb_bpp1 = sec_var->bits_per_pixel;
+ viafb_refresh1 = viafb_get_refresh(sec_var->xres, sec_var->yres,
+ long_refresh);
+}
+
+static int apply_device_setting(struct viafb_ioctl_setting setting_info,
+ struct fb_info *info)
+{
+ int need_set_mode = 0;
+ DEBUG_MSG(KERN_INFO "apply_device_setting\n");
+
+ if (setting_info.device_flag) {
+ need_set_mode = 1;
+ check_available_device_to_enable(setting_info.device_status);
+ }
+
+ /* Unlock LCD's operation according to LCD flag
+ and check if the setting value is valid. */
+ /* If the value is valid, apply the new setting value to the device. */
+ if (viafb_LCD_ON) {
+ if (setting_info.lcd_operation_flag & OP_LCD_CENTERING) {
+ need_set_mode = 1;
+ if (setting_info.lcd_attributes.display_center) {
+ /* Centering */
+ viaparinfo->lvds_setting_info->display_method =
+ LCD_CENTERING;
+ viafb_lcd_dsp_method = LCD_CENTERING;
+ viaparinfo->lvds_setting_info2->display_method =
+ viafb_lcd_dsp_method = LCD_CENTERING;
+ } else {
+ /* expandsion */
+ viaparinfo->lvds_setting_info->display_method =
+ LCD_EXPANDSION;
+ viafb_lcd_dsp_method = LCD_EXPANDSION;
+ viaparinfo->lvds_setting_info2->display_method =
+ LCD_EXPANDSION;
+ viafb_lcd_dsp_method = LCD_EXPANDSION;
+ }
+ }
+
+ if (setting_info.lcd_operation_flag & OP_LCD_MODE) {
+ need_set_mode = 1;
+ if (setting_info.lcd_attributes.lcd_mode ==
+ LCD_SPWG) {
+ viaparinfo->lvds_setting_info->lcd_mode =
+ viafb_lcd_mode = LCD_SPWG;
+ } else {
+ viaparinfo->lvds_setting_info->lcd_mode =
+ viafb_lcd_mode = LCD_OPENLDI;
+ }
+ viaparinfo->lvds_setting_info2->lcd_mode =
+ viaparinfo->lvds_setting_info->lcd_mode;
+ }
+
+ if (setting_info.lcd_operation_flag & OP_LCD_PANEL_ID) {
+ need_set_mode = 1;
+ if (setting_info.lcd_attributes.panel_id <=
+ LCD_PANEL_ID_MAXIMUM) {
+ viafb_lcd_panel_id =
+ setting_info.lcd_attributes.panel_id;
+ viafb_init_lcd_size();
+ }
+ }
+ }
+
+ if (0 != (setting_info.samm_status & OP_SAMM)) {
+ setting_info.samm_status =
+ setting_info.samm_status & (~OP_SAMM);
+ if (setting_info.samm_status == 0
+ || setting_info.samm_status == 1) {
+ viafb_SAMM_ON = setting_info.samm_status;
+
+ if (viafb_SAMM_ON)
+ viafb_primary_dev = setting_info.primary_device;
+
+ viafb_set_start_addr();
+ viafb_set_iga_path();
+ }
+ need_set_mode = 1;
+ }
+
+ viaparinfo->duoview = is_duoview();
+
+ if (!need_set_mode) {
+ ;
+ } else {
+ viafb_set_iga_path();
+ viafb_set_par(info);
+ }
+ return true;
+}
+
+static void retrieve_device_setting(struct viafb_ioctl_setting
+ *setting_info)
+{
+
+ /* get device status */
+ if (viafb_CRT_ON == 1)
+ setting_info->device_status = CRT_Device;
+ if (viafb_DVI_ON == 1)
+ setting_info->device_status |= DVI_Device;
+ if (viafb_LCD_ON == 1)
+ setting_info->device_status |= LCD_Device;
+ if (viafb_LCD2_ON == 1)
+ setting_info->device_status |= LCD2_Device;
+ if ((viaparinfo->video_on_crt == 1) && (viafb_CRT_ON == 1)) {
+ setting_info->video_device_status =
+ viaparinfo->crt_setting_info->iga_path;
+ } else if ((viaparinfo->video_on_dvi == 1) && (viafb_DVI_ON == 1)) {
+ setting_info->video_device_status =
+ viaparinfo->tmds_setting_info->iga_path;
+ } else if ((viaparinfo->video_on_lcd == 1) && (viafb_LCD_ON == 1)) {
+ setting_info->video_device_status =
+ viaparinfo->lvds_setting_info->iga_path;
+ } else {
+ setting_info->video_device_status = 0;
+ }
+
+ setting_info->samm_status = viafb_SAMM_ON;
+ setting_info->primary_device = get_primary_device();
+
+ setting_info->first_dev_bpp = viafb_bpp;
+ setting_info->second_dev_bpp = viafb_bpp1;
+
+ setting_info->first_dev_refresh = viafb_refresh;
+ setting_info->second_dev_refresh = viafb_refresh1;
+
+ setting_info->first_dev_hor_res = viafb_hotplug_Xres;
+ setting_info->first_dev_ver_res = viafb_hotplug_Yres;
+ setting_info->second_dev_hor_res = viafb_second_xres;
+ setting_info->second_dev_ver_res = viafb_second_yres;
+
+ /* Get lcd attributes */
+ setting_info->lcd_attributes.display_center = viafb_lcd_dsp_method;
+ setting_info->lcd_attributes.panel_id = viafb_lcd_panel_id;
+ setting_info->lcd_attributes.lcd_mode = viafb_lcd_mode;
+}
+
+static void parse_active_dev(void)
+{
+ viafb_CRT_ON = STATE_OFF;
+ viafb_DVI_ON = STATE_OFF;
+ viafb_LCD_ON = STATE_OFF;
+ viafb_LCD2_ON = STATE_OFF;
+ /* 1. Modify the active status of devices. */
+ /* 2. Keep the order of devices, so we can set corresponding
+ IGA path to devices in SAMM case. */
+ /* Note: The previous of active_dev is primary device,
+ and the following is secondary device. */
+ if (!strncmp(viafb_active_dev, "CRT+DVI", 7)) {
+ /* CRT+DVI */
+ viafb_CRT_ON = STATE_ON;
+ viafb_DVI_ON = STATE_ON;
+ viafb_primary_dev = CRT_Device;
+ } else if (!strncmp(viafb_active_dev, "DVI+CRT", 7)) {
+ /* DVI+CRT */
+ viafb_CRT_ON = STATE_ON;
+ viafb_DVI_ON = STATE_ON;
+ viafb_primary_dev = DVI_Device;
+ } else if (!strncmp(viafb_active_dev, "CRT+LCD", 7)) {
+ /* CRT+LCD */
+ viafb_CRT_ON = STATE_ON;
+ viafb_LCD_ON = STATE_ON;
+ viafb_primary_dev = CRT_Device;
+ } else if (!strncmp(viafb_active_dev, "LCD+CRT", 7)) {
+ /* LCD+CRT */
+ viafb_CRT_ON = STATE_ON;
+ viafb_LCD_ON = STATE_ON;
+ viafb_primary_dev = LCD_Device;
+ } else if (!strncmp(viafb_active_dev, "DVI+LCD", 7)) {
+ /* DVI+LCD */
+ viafb_DVI_ON = STATE_ON;
+ viafb_LCD_ON = STATE_ON;
+ viafb_primary_dev = DVI_Device;
+ } else if (!strncmp(viafb_active_dev, "LCD+DVI", 7)) {
+ /* LCD+DVI */
+ viafb_DVI_ON = STATE_ON;
+ viafb_LCD_ON = STATE_ON;
+ viafb_primary_dev = LCD_Device;
+ } else if (!strncmp(viafb_active_dev, "LCD+LCD2", 8)) {
+ viafb_LCD_ON = STATE_ON;
+ viafb_LCD2_ON = STATE_ON;
+ viafb_primary_dev = LCD_Device;
+ } else if (!strncmp(viafb_active_dev, "LCD2+LCD", 8)) {
+ viafb_LCD_ON = STATE_ON;
+ viafb_LCD2_ON = STATE_ON;
+ viafb_primary_dev = LCD2_Device;
+ } else if (!strncmp(viafb_active_dev, "CRT", 3)) {
+ /* CRT only */
+ viafb_CRT_ON = STATE_ON;
+ viafb_SAMM_ON = STATE_OFF;
+ } else if (!strncmp(viafb_active_dev, "DVI", 3)) {
+ /* DVI only */
+ viafb_DVI_ON = STATE_ON;
+ viafb_SAMM_ON = STATE_OFF;
+ } else if (!strncmp(viafb_active_dev, "LCD", 3)) {
+ /* LCD only */
+ viafb_LCD_ON = STATE_ON;
+ viafb_SAMM_ON = STATE_OFF;
+ } else {
+ viafb_CRT_ON = STATE_ON;
+ viafb_SAMM_ON = STATE_OFF;
+ }
+ viaparinfo->duoview = is_duoview();
+}
+
+static void parse_video_dev(void)
+{
+ viaparinfo->video_on_crt = STATE_OFF;
+ viaparinfo->video_on_dvi = STATE_OFF;
+ viaparinfo->video_on_lcd = STATE_OFF;
+
+ if (!strncmp(viafb_video_dev, "CRT", 3)) {
+ /* Video on CRT */
+ viaparinfo->video_on_crt = STATE_ON;
+ } else if (!strncmp(viafb_video_dev, "DVI", 3)) {
+ /* Video on DVI */
+ viaparinfo->video_on_dvi = STATE_ON;
+ } else if (!strncmp(viafb_video_dev, "LCD", 3)) {
+ /* Video on LCD */
+ viaparinfo->video_on_lcd = STATE_ON;
+ }
+}
+
+static int parse_port(char *opt_str, int *output_interface)
+{
+ if (!strncmp(opt_str, "DVP0", 4))
+ *output_interface = INTERFACE_DVP0;
+ else if (!strncmp(opt_str, "DVP1", 4))
+ *output_interface = INTERFACE_DVP1;
+ else if (!strncmp(opt_str, "DFP_HIGHLOW", 11))
+ *output_interface = INTERFACE_DFP;
+ else if (!strncmp(opt_str, "DFP_HIGH", 8))
+ *output_interface = INTERFACE_DFP_HIGH;
+ else if (!strncmp(opt_str, "DFP_LOW", 7))
+ *output_interface = INTERFACE_DFP_LOW;
+ else
+ *output_interface = INTERFACE_NONE;
+ return 0;
+}
+
+static void parse_lcd_port(void)
+{
+ parse_port(viafb_lcd_port, &viaparinfo->chip_info->lvds_chip_info.
+ output_interface);
+ /*Initialize to avoid unexpected behavior */
+ viaparinfo->chip_info->lvds_chip_info2.output_interface =
+ INTERFACE_NONE;
+
+ DEBUG_MSG(KERN_INFO "parse_lcd_port: viafb_lcd_port:%s,interface:%d\n",
+ viafb_lcd_port, viaparinfo->chip_info->lvds_chip_info.
+ output_interface);
+}
+
+static void parse_dvi_port(void)
+{
+ parse_port(viafb_dvi_port, &viaparinfo->chip_info->tmds_chip_info.
+ output_interface);
+
+ DEBUG_MSG(KERN_INFO "parse_dvi_port: viafb_dvi_port:%s,interface:%d\n",
+ viafb_dvi_port, viaparinfo->chip_info->tmds_chip_info.
+ output_interface);
+}
+
+/*
+ * The proc filesystem read/write function, a simple proc implement to
+ * get/set the value of DPA DVP0, DVP0DataDriving, DVP0ClockDriving, DVP1,
+ * DVP1Driving, DFPHigh, DFPLow CR96, SR2A[5], SR1B[1], SR2A[4], SR1E[2],
+ * CR9B, SR65, CR97, CR99
+ */
+static int viafb_dvp0_proc_read(char *buf, char **start, off_t offset,
+int count, int *eof, void *data)
+{
+ int len = 0;
+ u8 dvp0_data_dri = 0, dvp0_clk_dri = 0, dvp0 = 0;
+ dvp0_data_dri =
+ (viafb_read_reg(VIASR, SR2A) & BIT5) >> 4 |
+ (viafb_read_reg(VIASR, SR1B) & BIT1) >> 1;
+ dvp0_clk_dri =
+ (viafb_read_reg(VIASR, SR2A) & BIT4) >> 3 |
+ (viafb_read_reg(VIASR, SR1E) & BIT2) >> 2;
+ dvp0 = viafb_read_reg(VIACR, CR96) & 0x0f;
+ len +=
+ sprintf(buf + len, "%x %x %x\n", dvp0, dvp0_data_dri, dvp0_clk_dri);
+ *eof = 1; /*Inform kernel end of data */
+ return len;
+}
+static int viafb_dvp0_proc_write(struct file *file,
+ const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[20], *value, *pbuf;
+ u8 reg_val = 0;
+ unsigned long length, i;
+ if (count < 1)
+ return -EINVAL;
+ length = count > 20 ? 20 : count;
+ if (copy_from_user(&buf[0], buffer, length))
+ return -EFAULT;
+ buf[length - 1] = '\0'; /*Ensure end string */
+ pbuf = &buf[0];
+ for (i = 0; i < 3; i++) {
+ value = strsep(&pbuf, " ");
+ if (value != NULL) {
+ strict_strtoul(value, 0, (unsigned long *)&reg_val);
+ DEBUG_MSG(KERN_INFO "DVP0:reg_val[%l]=:%x\n", i,
+ reg_val);
+ switch (i) {
+ case 0:
+ viafb_write_reg_mask(CR96, VIACR,
+ reg_val, 0x0f);
+ break;
+ case 1:
+ viafb_write_reg_mask(SR2A, VIASR,
+ reg_val << 4, BIT5);
+ viafb_write_reg_mask(SR1B, VIASR,
+ reg_val << 1, BIT1);
+ break;
+ case 2:
+ viafb_write_reg_mask(SR2A, VIASR,
+ reg_val << 3, BIT4);
+ viafb_write_reg_mask(SR1E, VIASR,
+ reg_val << 2, BIT2);
+ break;
+ default:
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ return count;
+}
+static int viafb_dvp1_proc_read(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ u8 dvp1 = 0, dvp1_data_dri = 0, dvp1_clk_dri = 0;
+ dvp1 = viafb_read_reg(VIACR, CR9B) & 0x0f;
+ dvp1_data_dri = (viafb_read_reg(VIASR, SR65) & 0x0c) >> 2;
+ dvp1_clk_dri = viafb_read_reg(VIASR, SR65) & 0x03;
+ len +=
+ sprintf(buf + len, "%x %x %x\n", dvp1, dvp1_data_dri, dvp1_clk_dri);
+ *eof = 1; /*Inform kernel end of data */
+ return len;
+}
+static int viafb_dvp1_proc_write(struct file *file,
+ const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[20], *value, *pbuf;
+ u8 reg_val = 0;
+ unsigned long length, i;
+ if (count < 1)
+ return -EINVAL;
+ length = count > 20 ? 20 : count;
+ if (copy_from_user(&buf[0], buffer, length))
+ return -EFAULT;
+ buf[length - 1] = '\0'; /*Ensure end string */
+ pbuf = &buf[0];
+ for (i = 0; i < 3; i++) {
+ value = strsep(&pbuf, " ");
+ if (value != NULL) {
+ strict_strtoul(value, 0, (unsigned long *)&reg_val);
+ switch (i) {
+ case 0:
+ viafb_write_reg_mask(CR9B, VIACR,
+ reg_val, 0x0f);
+ break;
+ case 1:
+ viafb_write_reg_mask(SR65, VIASR,
+ reg_val << 2, 0x0c);
+ break;
+ case 2:
+ viafb_write_reg_mask(SR65, VIASR,
+ reg_val, 0x03);
+ break;
+ default:
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ return count;
+}
+
+static int viafb_dfph_proc_read(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ u8 dfp_high = 0;
+ dfp_high = viafb_read_reg(VIACR, CR97) & 0x0f;
+ len += sprintf(buf + len, "%x\n", dfp_high);
+ *eof = 1; /*Inform kernel end of data */
+ return len;
+}
+static int viafb_dfph_proc_write(struct file *file,
+ const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[20];
+ u8 reg_val = 0;
+ unsigned long length;
+ if (count < 1)
+ return -EINVAL;
+ length = count > 20 ? 20 : count;
+ if (copy_from_user(&buf[0], buffer, length))
+ return -EFAULT;
+ buf[length - 1] = '\0'; /*Ensure end string */
+ strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+ viafb_write_reg_mask(CR97, VIACR, reg_val, 0x0f);
+ return count;
+}
+static int viafb_dfpl_proc_read(char *buf, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int len = 0;
+ u8 dfp_low = 0;
+ dfp_low = viafb_read_reg(VIACR, CR99) & 0x0f;
+ len += sprintf(buf + len, "%x\n", dfp_low);
+ *eof = 1; /*Inform kernel end of data */
+ return len;
+}
+static int viafb_dfpl_proc_write(struct file *file,
+ const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[20];
+ u8 reg_val = 0;
+ unsigned long length;
+ if (count < 1)
+ return -EINVAL;
+ length = count > 20 ? 20 : count;
+ if (copy_from_user(&buf[0], buffer, length))
+ return -EFAULT;
+ buf[length - 1] = '\0'; /*Ensure end string */
+ strict_strtoul(&buf[0], 0, (unsigned long *)&reg_val);
+ viafb_write_reg_mask(CR99, VIACR, reg_val, 0x0f);
+ return count;
+}
+static int viafb_vt1636_proc_read(char *buf, char **start,
+ off_t offset, int count, int *eof, void *data)
+{
+ int len = 0;
+ u8 vt1636_08 = 0, vt1636_09 = 0;
+ switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ case VT1636_LVDS:
+ vt1636_08 =
+ viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info, 0x08) & 0x0f;
+ vt1636_09 =
+ viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info,
+ &viaparinfo->chip_info->lvds_chip_info, 0x09) & 0x1f;
+ len += sprintf(buf + len, "%x %x\n", vt1636_08, vt1636_09);
+ break;
+ default:
+ break;
+ }
+ switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+ case VT1636_LVDS:
+ vt1636_08 =
+ viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2, 0x08) & 0x0f;
+ vt1636_09 =
+ viafb_gpio_i2c_read_lvds(viaparinfo->lvds_setting_info2,
+ &viaparinfo->chip_info->lvds_chip_info2, 0x09) & 0x1f;
+ len += sprintf(buf + len, " %x %x\n", vt1636_08, vt1636_09);
+ break;
+ default:
+ break;
+ }
+ *eof = 1; /*Inform kernel end of data */
+ return len;
+}
+static int viafb_vt1636_proc_write(struct file *file,
+ const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[30], *value, *pbuf;
+ struct IODATA reg_val;
+ unsigned long length, i;
+ if (count < 1)
+ return -EINVAL;
+ length = count > 30 ? 30 : count;
+ if (copy_from_user(&buf[0], buffer, length))
+ return -EFAULT;
+ buf[length - 1] = '\0'; /*Ensure end string */
+ pbuf = &buf[0];
+ switch (viaparinfo->chip_info->lvds_chip_info.lvds_chip_name) {
+ case VT1636_LVDS:
+ for (i = 0; i < 2; i++) {
+ value = strsep(&pbuf, " ");
+ if (value != NULL) {
+ strict_strtoul(value, 0,
+ (unsigned long *)&reg_val.Data);
+ switch (i) {
+ case 0:
+ reg_val.Index = 0x08;
+ reg_val.Mask = 0x0f;
+ viafb_gpio_i2c_write_mask_lvds
+ (viaparinfo->lvds_setting_info,
+ &viaparinfo->
+ chip_info->lvds_chip_info,
+ reg_val);
+ break;
+ case 1:
+ reg_val.Index = 0x09;
+ reg_val.Mask = 0x1f;
+ viafb_gpio_i2c_write_mask_lvds
+ (viaparinfo->lvds_setting_info,
+ &viaparinfo->
+ chip_info->lvds_chip_info,
+ reg_val);
+ break;
+ default:
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ switch (viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+ case VT1636_LVDS:
+ for (i = 0; i < 2; i++) {
+ value = strsep(&pbuf, " ");
+ if (value != NULL) {
+ strict_strtoul(value, 0,
+ (unsigned long *)&reg_val.Data);
+ switch (i) {
+ case 0:
+ reg_val.Index = 0x08;
+ reg_val.Mask = 0x0f;
+ viafb_gpio_i2c_write_mask_lvds
+ (viaparinfo->lvds_setting_info2,
+ &viaparinfo->
+ chip_info->lvds_chip_info2,
+ reg_val);
+ break;
+ case 1:
+ reg_val.Index = 0x09;
+ reg_val.Mask = 0x1f;
+ viafb_gpio_i2c_write_mask_lvds
+ (viaparinfo->lvds_setting_info2,
+ &viaparinfo->
+ chip_info->lvds_chip_info2,
+ reg_val);
+ break;
+ default:
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return count;
+}
+
+static void viafb_init_proc(struct proc_dir_entry *viafb_entry)
+{
+ struct proc_dir_entry *entry;
+ viafb_entry = proc_mkdir("viafb", NULL);
+ if (viafb_entry) {
+ entry = create_proc_entry("dvp0", 0, viafb_entry);
+ if (entry) {
+ entry->owner = THIS_MODULE;
+ entry->read_proc = viafb_dvp0_proc_read;
+ entry->write_proc = viafb_dvp0_proc_write;
+ }
+ entry = create_proc_entry("dvp1", 0, viafb_entry);
+ if (entry) {
+ entry->owner = THIS_MODULE;
+ entry->read_proc = viafb_dvp1_proc_read;
+ entry->write_proc = viafb_dvp1_proc_write;
+ }
+ entry = create_proc_entry("dfph", 0, viafb_entry);
+ if (entry) {
+ entry->owner = THIS_MODULE;
+ entry->read_proc = viafb_dfph_proc_read;
+ entry->write_proc = viafb_dfph_proc_write;
+ }
+ entry = create_proc_entry("dfpl", 0, viafb_entry);
+ if (entry) {
+ entry->owner = THIS_MODULE;
+ entry->read_proc = viafb_dfpl_proc_read;
+ entry->write_proc = viafb_dfpl_proc_write;
+ }
+ if (VT1636_LVDS == viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_name || VT1636_LVDS ==
+ viaparinfo->chip_info->lvds_chip_info2.lvds_chip_name) {
+ entry = create_proc_entry("vt1636", 0, viafb_entry);
+ if (entry) {
+ entry->owner = THIS_MODULE;
+ entry->read_proc = viafb_vt1636_proc_read;
+ entry->write_proc = viafb_vt1636_proc_write;
+ }
+ }
+
+ }
+}
+static void viafb_remove_proc(struct proc_dir_entry *viafb_entry)
+{
+ /* no problem if it was not registered */
+ remove_proc_entry("dvp0", viafb_entry);/* parent dir */
+ remove_proc_entry("dvp1", viafb_entry);
+ remove_proc_entry("dfph", viafb_entry);
+ remove_proc_entry("dfpl", viafb_entry);
+ remove_proc_entry("vt1636", viafb_entry);
+ remove_proc_entry("vt1625", viafb_entry);
+}
+
+static int __devinit via_pci_probe(void)
+{
+ unsigned int default_xres, default_yres;
+ char *tmpc, *tmpm;
+ char *tmpc_sec, *tmpm_sec;
+ int vmode_index;
+ u32 tmds_length, lvds_length, crt_length, chip_length, viafb_par_length;
+
+ DEBUG_MSG(KERN_INFO "VIAFB PCI Probe!!\n");
+
+ viafb_par_length = ALIGN(sizeof(struct viafb_par), BITS_PER_LONG/8);
+ tmds_length = ALIGN(sizeof(struct tmds_setting_information),
+ BITS_PER_LONG/8);
+ lvds_length = ALIGN(sizeof(struct lvds_setting_information),
+ BITS_PER_LONG/8);
+ crt_length = ALIGN(sizeof(struct lvds_setting_information),
+ BITS_PER_LONG/8);
+ chip_length = ALIGN(sizeof(struct chip_information), BITS_PER_LONG/8);
+
+ /* Allocate fb_info and ***_par here, also including some other needed
+ * variables
+ */
+ viafbinfo = framebuffer_alloc(viafb_par_length + 2 * lvds_length +
+ tmds_length + crt_length + chip_length, NULL);
+ if (!viafbinfo) {
+ printk(KERN_ERR"Could not allocate memory for viafb_info.\n");
+ return -ENODEV;
+ }
+
+ viaparinfo = (struct viafb_par *)viafbinfo->par;
+ viaparinfo->tmds_setting_info = (struct tmds_setting_information *)
+ ((unsigned long)viaparinfo + viafb_par_length);
+ viaparinfo->lvds_setting_info = (struct lvds_setting_information *)
+ ((unsigned long)viaparinfo->tmds_setting_info + tmds_length);
+ viaparinfo->lvds_setting_info2 = (struct lvds_setting_information *)
+ ((unsigned long)viaparinfo->lvds_setting_info + lvds_length);
+ viaparinfo->crt_setting_info = (struct crt_setting_information *)
+ ((unsigned long)viaparinfo->lvds_setting_info2 + lvds_length);
+ viaparinfo->chip_info = (struct chip_information *)
+ ((unsigned long)viaparinfo->crt_setting_info + crt_length);
+
+ if (viafb_dual_fb)
+ viafb_SAMM_ON = 1;
+ parse_active_dev();
+ parse_video_dev();
+ parse_lcd_port();
+ parse_dvi_port();
+
+ /* for dual-fb must viafb_SAMM_ON=1 and viafb_dual_fb=1 */
+ if (!viafb_SAMM_ON)
+ viafb_dual_fb = 0;
+
+ /* Set up I2C bus stuff */
+ viafb_create_i2c_bus(viaparinfo);
+
+ viafb_init_chip_info();
+ viafb_get_fb_info(&viaparinfo->fbmem, &viaparinfo->memsize);
+ viaparinfo->fbmem_free = viaparinfo->memsize;
+ viaparinfo->fbmem_used = 0;
+ viaparinfo->fbmem_virt = ioremap_nocache(viaparinfo->fbmem,
+ viaparinfo->memsize);
+ viafbinfo->screen_base = (char *)viaparinfo->fbmem_virt;
+
+ if (!viaparinfo->fbmem_virt) {
+ printk(KERN_INFO "ioremap failed\n");
+ return -1;
+ }
+
+ viafb_get_mmio_info(&viaparinfo->mmio_base, &viaparinfo->mmio_len);
+ viaparinfo->io_virt = ioremap_nocache(viaparinfo->mmio_base,
+ viaparinfo->mmio_len);
+
+ viafbinfo->node = 0;
+ viafbinfo->fbops = &viafb_ops;
+ viafbinfo->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN;
+
+ viafbinfo->pseudo_palette = pseudo_pal;
+ if (viafb_accel) {
+ viafb_init_accel();
+ viafb_init_2d_engine();
+ viafb_hw_cursor_init();
+ }
+
+ if (viafb_second_size && (viafb_second_size < 8)) {
+ viafb_second_offset = viaparinfo->fbmem_free -
+ viafb_second_size * 1024 * 1024;
+ } else {
+ viafb_second_size = 8;
+ viafb_second_offset = viaparinfo->fbmem_free -
+ viafb_second_size * 1024 * 1024;
+ }
+
+ viafb_FB_MM = viaparinfo->fbmem_virt;
+ tmpm = viafb_mode;
+ tmpc = strsep(&tmpm, "x");
+ strict_strtoul(tmpc, 0, (unsigned long *)&default_xres);
+ strict_strtoul(tmpm, 0, (unsigned long *)&default_yres);
+
+ vmode_index = viafb_get_mode_index(default_xres, default_yres, 0);
+ DEBUG_MSG(KERN_INFO "0->index=%d\n", vmode_index);
+
+ if (viafb_SAMM_ON == 1) {
+ if (strcmp(viafb_mode, viafb_mode1)) {
+ tmpm_sec = viafb_mode1;
+ tmpc_sec = strsep(&tmpm_sec, "x");
+ strict_strtoul(tmpc_sec, 0,
+ (unsigned long *)&viafb_second_xres);
+ strict_strtoul(tmpm_sec, 0,
+ (unsigned long *)&viafb_second_yres);
+ } else {
+ viafb_second_xres = default_xres;
+ viafb_second_yres = default_yres;
+ }
+ if (0 == viafb_second_virtual_xres) {
+ switch (viafb_second_xres) {
+ case 1400:
+ viafb_second_virtual_xres = 1408;
+ break;
+ default:
+ viafb_second_virtual_xres = viafb_second_xres;
+ break;
+ }
+ }
+ if (0 == viafb_second_virtual_yres)
+ viafb_second_virtual_yres = viafb_second_yres;
+ }
+
+ switch (viafb_bpp) {
+ case 0 ... 8:
+ viafb_bpp = 8;
+ break;
+ case 9 ... 16:
+ viafb_bpp = 16;
+ break;
+ case 17 ... 32:
+ viafb_bpp = 32;
+ break;
+ default:
+ viafb_bpp = 8;
+ }
+ default_var.xres = default_xres;
+ default_var.yres = default_yres;
+ switch (default_xres) {
+ case 1400:
+ default_var.xres_virtual = 1408;
+ break;
+ default:
+ default_var.xres_virtual = default_xres;
+ break;
+ }
+ default_var.yres_virtual = default_yres;
+ default_var.bits_per_pixel = viafb_bpp;
+ if (default_var.bits_per_pixel == 15)
+ default_var.bits_per_pixel = 16;
+ default_var.pixclock =
+ viafb_get_pixclock(default_xres, default_yres, viafb_refresh);
+ default_var.left_margin = (default_xres >> 3) & 0xf8;
+ default_var.right_margin = 32;
+ default_var.upper_margin = 16;
+ default_var.lower_margin = 4;
+ default_var.hsync_len = default_var.left_margin;
+ default_var.vsync_len = 4;
+ default_var.accel_flags = 0;
+
+ if (viafb_accel) {
+ viafbinfo->flags |=
+ (FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
+ FBINFO_HWACCEL_IMAGEBLIT);
+ default_var.accel_flags |= FB_ACCELF_TEXT;
+ } else
+ viafbinfo->flags |= FBINFO_HWACCEL_DISABLED;
+
+ if (viafb_dual_fb) {
+ viafbinfo1 = framebuffer_alloc(viafb_par_length, NULL);
+ if (!viafbinfo1) {
+ printk(KERN_ERR
+ "allocate the second framebuffer struct error\n");
+ framebuffer_release(viafbinfo);
+ return -ENOMEM;
+ }
+ viaparinfo1 = viafbinfo1->par;
+ memcpy(viaparinfo1, viaparinfo, viafb_par_length);
+ viaparinfo1->memsize = viaparinfo->memsize -
+ viafb_second_offset;
+ viaparinfo->memsize = viafb_second_offset;
+ viaparinfo1->fbmem_virt = viaparinfo->fbmem_virt +
+ viafb_second_offset;
+ viaparinfo1->fbmem = viaparinfo->fbmem + viafb_second_offset;
+
+ viaparinfo1->fbmem_used = viaparinfo->fbmem_used;
+ viaparinfo1->fbmem_free = viaparinfo1->memsize -
+ viaparinfo1->fbmem_used;
+ viaparinfo->fbmem_free = viaparinfo->memsize;
+ viaparinfo->fbmem_used = 0;
+ if (viafb_accel) {
+ viaparinfo1->cursor_start =
+ viaparinfo->cursor_start - viafb_second_offset;
+ viaparinfo1->VQ_start = viaparinfo->VQ_start -
+ viafb_second_offset;
+ viaparinfo1->VQ_end = viaparinfo->VQ_end -
+ viafb_second_offset;
+ }
+
+ memcpy(viafbinfo1, viafbinfo, sizeof(struct fb_info));
+ viafbinfo1->screen_base = viafbinfo->screen_base +
+ viafb_second_offset;
+ viafbinfo1->fix.smem_start = viaparinfo1->fbmem;
+ viafbinfo1->fix.smem_len = viaparinfo1->fbmem_free;
+
+ default_var.xres = viafb_second_xres;
+ default_var.yres = viafb_second_yres;
+ default_var.xres_virtual = viafb_second_virtual_xres;
+ default_var.yres_virtual = viafb_second_virtual_yres;
+ if (viafb_bpp1 != viafb_bpp)
+ viafb_bpp1 = viafb_bpp;
+ default_var.bits_per_pixel = viafb_bpp1;
+ default_var.pixclock =
+ viafb_get_pixclock(viafb_second_xres, viafb_second_yres,
+ viafb_refresh);
+ default_var.left_margin = (viafb_second_xres >> 3) & 0xf8;
+ default_var.right_margin = 32;
+ default_var.upper_margin = 16;
+ default_var.lower_margin = 4;
+ default_var.hsync_len = default_var.left_margin;
+ default_var.vsync_len = 4;
+
+ viafb_setup_fixinfo(&viafbinfo1->fix, viaparinfo1);
+ viafb_check_var(&default_var, viafbinfo1);
+ viafbinfo1->var = default_var;
+ viafb_update_viafb_par(viafbinfo);
+ viafb_update_fix(&viafbinfo1->fix, viafbinfo1);
+ }
+
+ viafb_setup_fixinfo(&viafbinfo->fix, viaparinfo);
+ viafb_check_var(&default_var, viafbinfo);
+ viafbinfo->var = default_var;
+ viafb_update_viafb_par(viafbinfo);
+ viafb_update_fix(&viafbinfo->fix, viafbinfo);
+ default_var.activate = FB_ACTIVATE_NOW;
+ fb_alloc_cmap(&viafbinfo->cmap, 256, 0);
+
+ if (viafb_dual_fb && (viafb_primary_dev == LCD_Device)
+ && (viaparinfo->chip_info->gfx_chip_name == UNICHROME_CLE266)) {
+ if (register_framebuffer(viafbinfo1) < 0)
+ return -EINVAL;
+ }
+ if (register_framebuffer(viafbinfo) < 0)
+ return -EINVAL;
+
+ if (viafb_dual_fb && ((viafb_primary_dev != LCD_Device)
+ || (viaparinfo->chip_info->gfx_chip_name !=
+ UNICHROME_CLE266))) {
+ if (register_framebuffer(viafbinfo1) < 0)
+ return -EINVAL;
+ }
+ DEBUG_MSG(KERN_INFO "fb%d: %s frame buffer device %dx%d-%dbpp\n",
+ viafbinfo->node, viafbinfo->fix.id, default_var.xres,
+ default_var.yres, default_var.bits_per_pixel);
+
+ viafb_init_proc(viaparinfo->proc_entry);
+ viafb_init_dac(IGA2);
+ return 0;
+}
+
+static void __devexit via_pci_remove(void)
+{
+ DEBUG_MSG(KERN_INFO "via_pci_remove!\n");
+ fb_dealloc_cmap(&viafbinfo->cmap);
+ unregister_framebuffer(viafbinfo);
+ if (viafb_dual_fb)
+ unregister_framebuffer(viafbinfo1);
+ iounmap((void *)viaparinfo->fbmem_virt);
+ iounmap(viaparinfo->io_virt);
+
+ viafb_delete_i2c_buss(viaparinfo);
+
+ framebuffer_release(viafbinfo);
+ if (viafb_dual_fb)
+ framebuffer_release(viafbinfo1);
+
+ viafb_remove_proc(viaparinfo->proc_entry);
+}
+
+#ifndef MODULE
+static int __init viafb_setup(char *options)
+{
+ char *this_opt;
+ DEBUG_MSG(KERN_INFO "viafb_setup!\n");
+
+ if (!options || !*options)
+ return 0;
+
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ if (!*this_opt)
+ continue;
+
+ if (!strncmp(this_opt, "viafb_mode1=", 12))
+ viafb_mode1 = kstrdup(this_opt + 12, GFP_KERNEL);
+ else if (!strncmp(this_opt, "viafb_mode=", 11))
+ viafb_mode = kstrdup(this_opt + 11, GFP_KERNEL);
+ else if (!strncmp(this_opt, "viafb_bpp1=", 11))
+ strict_strtoul(this_opt + 11, 0,
+ (unsigned long *)&viafb_bpp1);
+ else if (!strncmp(this_opt, "viafb_bpp=", 10))
+ strict_strtoul(this_opt + 10, 0,
+ (unsigned long *)&viafb_bpp);
+ else if (!strncmp(this_opt, "viafb_refresh1=", 15))
+ strict_strtoul(this_opt + 15, 0,
+ (unsigned long *)&viafb_refresh1);
+ else if (!strncmp(this_opt, "viafb_refresh=", 14))
+ strict_strtoul(this_opt + 14, 0,
+ (unsigned long *)&viafb_refresh);
+ else if (!strncmp(this_opt, "viafb_lcd_dsp_method=", 21))
+ strict_strtoul(this_opt + 21, 0,
+ (unsigned long *)&viafb_lcd_dsp_method);
+ else if (!strncmp(this_opt, "viafb_lcd_panel_id=", 19))
+ strict_strtoul(this_opt + 19, 0,
+ (unsigned long *)&viafb_lcd_panel_id);
+ else if (!strncmp(this_opt, "viafb_accel=", 12))
+ strict_strtoul(this_opt + 12, 0,
+ (unsigned long *)&viafb_accel);
+ else if (!strncmp(this_opt, "viafb_SAMM_ON=", 14))
+ strict_strtoul(this_opt + 14, 0,
+ (unsigned long *)&viafb_SAMM_ON);
+ else if (!strncmp(this_opt, "viafb_active_dev=", 17))
+ viafb_active_dev = kstrdup(this_opt + 17, GFP_KERNEL);
+ else if (!strncmp(this_opt,
+ "viafb_display_hardware_layout=", 30))
+ strict_strtoul(this_opt + 30, 0,
+ (unsigned long *)&viafb_display_hardware_layout);
+ else if (!strncmp(this_opt, "viafb_second_size=", 18))
+ strict_strtoul(this_opt + 18, 0,
+ (unsigned long *)&viafb_second_size);
+ else if (!strncmp(this_opt,
+ "viafb_platform_epia_dvi=", 24))
+ strict_strtoul(this_opt + 24, 0,
+ (unsigned long *)&viafb_platform_epia_dvi);
+ else if (!strncmp(this_opt,
+ "viafb_device_lcd_dualedge=", 26))
+ strict_strtoul(this_opt + 26, 0,
+ (unsigned long *)&viafb_device_lcd_dualedge);
+ else if (!strncmp(this_opt, "viafb_bus_width=", 16))
+ strict_strtoul(this_opt + 16, 0,
+ (unsigned long *)&viafb_bus_width);
+ else if (!strncmp(this_opt, "viafb_lcd_mode=", 15))
+ strict_strtoul(this_opt + 15, 0,
+ (unsigned long *)&viafb_lcd_mode);
+ else if (!strncmp(this_opt, "viafb_video_dev=", 16))
+ viafb_video_dev = kstrdup(this_opt + 16, GFP_KERNEL);
+ else if (!strncmp(this_opt, "viafb_lcd_port=", 15))
+ viafb_lcd_port = kstrdup(this_opt + 15, GFP_KERNEL);
+ else if (!strncmp(this_opt, "viafb_dvi_port=", 15))
+ viafb_dvi_port = kstrdup(this_opt + 15, GFP_KERNEL);
+ }
+ return 0;
+}
+#endif
+
+static int __init viafb_init(void)
+{
+#ifndef MODULE
+ char *option = NULL;
+ if (fb_get_options("viafb", &option))
+ return -ENODEV;
+ viafb_setup(option);
+#endif
+ printk(KERN_INFO
+ "VIA Graphics Intergration Chipset framebuffer %d.%d initializing\n",
+ VERSION_MAJOR, VERSION_MINOR);
+ return via_pci_probe();
+}
+
+static void __exit viafb_exit(void)
+{
+ DEBUG_MSG(KERN_INFO "viafb_exit!\n");
+ via_pci_remove();
+}
+
+static struct fb_ops viafb_ops = {
+ .owner = THIS_MODULE,
+ .fb_open = viafb_open,
+ .fb_release = viafb_release,
+ .fb_check_var = viafb_check_var,
+ .fb_set_par = viafb_set_par,
+ .fb_setcolreg = viafb_setcolreg,
+ .fb_pan_display = viafb_pan_display,
+ .fb_blank = viafb_blank,
+ .fb_fillrect = viafb_fillrect,
+ .fb_copyarea = viafb_copyarea,
+ .fb_imageblit = viafb_imageblit,
+ .fb_cursor = viafb_cursor,
+ .fb_ioctl = viafb_ioctl,
+ .fb_sync = viafb_sync,
+ .fb_setcmap = viafb_setcmap,
+};
+
+module_init(viafb_init);
+module_exit(viafb_exit);
+
+#ifdef MODULE
+module_param(viafb_memsize, int, 0);
+
+module_param(viafb_mode, charp, 0);
+MODULE_PARM_DESC(viafb_mode, "Set resolution (default=640x480)");
+
+module_param(viafb_mode1, charp, 0);
+MODULE_PARM_DESC(viafb_mode1, "Set resolution (default=640x480)");
+
+module_param(viafb_bpp, int, 0);
+MODULE_PARM_DESC(viafb_bpp, "Set color depth (default=32bpp)");
+
+module_param(viafb_bpp1, int, 0);
+MODULE_PARM_DESC(viafb_bpp1, "Set color depth (default=32bpp)");
+
+module_param(viafb_refresh, int, 0);
+MODULE_PARM_DESC(viafb_refresh,
+ "Set CRT viafb_refresh rate (default = 60)");
+
+module_param(viafb_refresh1, int, 0);
+MODULE_PARM_DESC(viafb_refresh1,
+ "Set CRT refresh rate (default = 60)");
+
+module_param(viafb_lcd_panel_id, int, 0);
+MODULE_PARM_DESC(viafb_lcd_panel_id,
+ "Set Flat Panel type(Default=1024x768)");
+
+module_param(viafb_lcd_dsp_method, int, 0);
+MODULE_PARM_DESC(viafb_lcd_dsp_method,
+ "Set Flat Panel display scaling method.(Default=Expandsion)");
+
+module_param(viafb_SAMM_ON, int, 0);
+MODULE_PARM_DESC(viafb_SAMM_ON,
+ "Turn on/off flag of SAMM(Default=OFF)");
+
+module_param(viafb_accel, int, 0);
+MODULE_PARM_DESC(viafb_accel,
+ "Set 2D Hardware Acceleration.(Default = OFF)");
+
+module_param(viafb_active_dev, charp, 0);
+MODULE_PARM_DESC(viafb_active_dev, "Specify active devices.");
+
+module_param(viafb_display_hardware_layout, int, 0);
+MODULE_PARM_DESC(viafb_display_hardware_layout,
+ "Display Hardware Layout (LCD Only, DVI Only...,etc)");
+
+module_param(viafb_second_size, int, 0);
+MODULE_PARM_DESC(viafb_second_size,
+ "Set secondary device memory size");
+
+module_param(viafb_dual_fb, int, 0);
+MODULE_PARM_DESC(viafb_dual_fb,
+ "Turn on/off flag of dual framebuffer devices.(Default = OFF)");
+
+module_param(viafb_platform_epia_dvi, int, 0);
+MODULE_PARM_DESC(viafb_platform_epia_dvi,
+ "Turn on/off flag of DVI devices on EPIA board.(Default = OFF)");
+
+module_param(viafb_device_lcd_dualedge, int, 0);
+MODULE_PARM_DESC(viafb_device_lcd_dualedge,
+ "Turn on/off flag of dual edge panel.(Default = OFF)");
+
+module_param(viafb_bus_width, int, 0);
+MODULE_PARM_DESC(viafb_bus_width,
+ "Set bus width of panel.(Default = 12)");
+
+module_param(viafb_lcd_mode, int, 0);
+MODULE_PARM_DESC(viafb_lcd_mode,
+ "Set Flat Panel mode(Default=OPENLDI)");
+
+module_param(viafb_video_dev, charp, 0);
+MODULE_PARM_DESC(viafb_video_dev, "Specify video devices.");
+
+module_param(viafb_lcd_port, charp, 0);
+MODULE_PARM_DESC(viafb_lcd_port, "Specify LCD output port.");
+
+module_param(viafb_dvi_port, charp, 0);
+MODULE_PARM_DESC(viafb_dvi_port, "Specify DVI output port.");
+
+MODULE_LICENSE("GPL");
+#endif
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h
new file mode 100644
index 00000000000..a4158e87287
--- /dev/null
+++ b/drivers/video/via/viafbdev.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __VIAFBDEV_H__
+#define __VIAFBDEV_H__
+
+#include <linux/proc_fs.h>
+#include <linux/fb.h>
+
+#include "ioctl.h"
+#include "share.h"
+#include "chip.h"
+#include "hw.h"
+#include "via_i2c.h"
+
+#define VERSION_MAJOR 2
+#define VERSION_KERNEL 6 /* For kernel 2.6 */
+
+#define VERSION_OS 0 /* 0: for 32 bits OS, 1: for 64 bits OS */
+#define VERSION_MINOR 4
+
+struct viafb_par {
+ int bpp;
+ int hres;
+ int vres;
+ int linelength;
+ u32 xoffset;
+ u32 yoffset;
+
+ void __iomem *fbmem_virt; /*framebuffer virtual memory address */
+ void __iomem *io_virt; /*iospace virtual memory address */
+ unsigned int fbmem; /*framebuffer physical memory address */
+ unsigned int memsize; /*size of fbmem */
+ unsigned int io; /*io space address */
+ unsigned long mmio_base; /*mmio base address */
+ unsigned long mmio_len; /*mmio base length */
+ u32 fbmem_free; /* Free FB memory */
+ u32 fbmem_used; /* Use FB memory size */
+ u32 cursor_start; /* Cursor Start Address */
+ u32 VQ_start; /* Virtual Queue Start Address */
+ u32 VQ_end; /* Virtual Queue End Address */
+ u32 iga_path;
+ struct proc_dir_entry *proc_entry; /*viafb proc entry */
+ u8 duoview; /*Is working in duoview mode? */
+
+ /* I2C stuff */
+ struct via_i2c_stuff i2c_stuff;
+
+ /* All the information will be needed to set engine */
+ struct tmds_setting_information *tmds_setting_info;
+ struct crt_setting_information *crt_setting_info;
+ struct lvds_setting_information *lvds_setting_info;
+ struct lvds_setting_information *lvds_setting_info2;
+ struct chip_information *chip_info;
+
+ /* some information related to video playing */
+ int video_on_crt;
+ int video_on_dvi;
+ int video_on_lcd;
+
+};
+struct viafb_modeinfo {
+ u32 xres;
+ u32 yres;
+ int mode_index;
+ char *mode_res;
+};
+extern unsigned int viafb_second_virtual_yres;
+extern unsigned int viafb_second_virtual_xres;
+extern unsigned int viafb_second_offset;
+extern int viafb_second_size;
+extern int viafb_SAMM_ON;
+extern int viafb_dual_fb;
+extern int viafb_LCD2_ON;
+extern int viafb_LCD_ON;
+extern int viafb_DVI_ON;
+extern int viafb_accel;
+extern int viafb_hotplug;
+extern int viafb_memsize;
+
+extern int strict_strtoul(const char *cp, unsigned int base,
+ unsigned long *res);
+
+void viafb_memory_pitch_patch(struct fb_info *info);
+void viafb_fill_var_timing_info(struct fb_var_screeninfo *var, int refresh,
+ int mode_index);
+int viafb_get_mode_index(int hres, int vres, int flag);
+u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information
+ *plvds_chip_info, u8 index);
+void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information
+ *plvds_chip_info, struct IODATA io_data);
+#endif /* __VIAFBDEV_H__ */
diff --git a/drivers/video/via/viamode.c b/drivers/video/via/viamode.c
new file mode 100644
index 00000000000..6dcf583a837
--- /dev/null
+++ b/drivers/video/via/viamode.c
@@ -0,0 +1,1086 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+struct res_map_refresh res_map_refresh_tbl[] = {
+/*hres, vres, vclock, vmode_refresh*/
+ {480, 640, RES_480X640_60HZ_PIXCLOCK, 60},
+ {640, 480, RES_640X480_60HZ_PIXCLOCK, 60},
+ {640, 480, RES_640X480_75HZ_PIXCLOCK, 75},
+ {640, 480, RES_640X480_85HZ_PIXCLOCK, 85},
+ {640, 480, RES_640X480_100HZ_PIXCLOCK, 100},
+ {640, 480, RES_640X480_120HZ_PIXCLOCK, 120},
+ {720, 480, RES_720X480_60HZ_PIXCLOCK, 60},
+ {720, 576, RES_720X576_60HZ_PIXCLOCK, 60},
+ {800, 480, RES_800X480_60HZ_PIXCLOCK, 60},
+ {800, 600, RES_800X600_60HZ_PIXCLOCK, 60},
+ {800, 600, RES_800X600_75HZ_PIXCLOCK, 75},
+ {800, 600, RES_800X600_85HZ_PIXCLOCK, 85},
+ {800, 600, RES_800X600_100HZ_PIXCLOCK, 100},
+ {800, 600, RES_800X600_120HZ_PIXCLOCK, 120},
+ {848, 480, RES_848X480_60HZ_PIXCLOCK, 60},
+ {856, 480, RES_856X480_60HZ_PIXCLOCK, 60},
+ {1024, 512, RES_1024X512_60HZ_PIXCLOCK, 60},
+ {1024, 600, RES_1024X600_60HZ_PIXCLOCK, 60},
+ {1024, 768, RES_1024X768_60HZ_PIXCLOCK, 60},
+ {1024, 768, RES_1024X768_75HZ_PIXCLOCK, 75},
+ {1024, 768, RES_1024X768_85HZ_PIXCLOCK, 85},
+ {1024, 768, RES_1024X768_100HZ_PIXCLOCK, 100},
+/* {1152,864, RES_1152X864_70HZ_PIXCLOCK, 70},*/
+ {1152, 864, RES_1152X864_75HZ_PIXCLOCK, 75},
+ {1280, 768, RES_1280X768_60HZ_PIXCLOCK, 60},
+ {1280, 800, RES_1280X800_60HZ_PIXCLOCK, 60},
+ {1280, 960, RES_1280X960_60HZ_PIXCLOCK, 60},
+ {1280, 1024, RES_1280X1024_60HZ_PIXCLOCK, 60},
+ {1280, 1024, RES_1280X1024_75HZ_PIXCLOCK, 75},
+ {1280, 1024, RES_1280X768_85HZ_PIXCLOCK, 85},
+ {1440, 1050, RES_1440X1050_60HZ_PIXCLOCK, 60},
+ {1600, 1200, RES_1600X1200_60HZ_PIXCLOCK, 60},
+ {1600, 1200, RES_1600X1200_75HZ_PIXCLOCK, 75},
+ {1280, 720, RES_1280X720_60HZ_PIXCLOCK, 60},
+ {1920, 1080, RES_1920X1080_60HZ_PIXCLOCK, 60},
+ {1400, 1050, RES_1400X1050_60HZ_PIXCLOCK, 60},
+ {1400, 1050, RES_1400X1050_75HZ_PIXCLOCK, 75},
+ {1368, 768, RES_1368X768_60HZ_PIXCLOCK, 60},
+ {960, 600, RES_960X600_60HZ_PIXCLOCK, 60},
+ {1000, 600, RES_1000X600_60HZ_PIXCLOCK, 60},
+ {1024, 576, RES_1024X576_60HZ_PIXCLOCK, 60},
+ {1088, 612, RES_1088X612_60HZ_PIXCLOCK, 60},
+ {1152, 720, RES_1152X720_60HZ_PIXCLOCK, 60},
+ {1200, 720, RES_1200X720_60HZ_PIXCLOCK, 60},
+ {1280, 600, RES_1280X600_60HZ_PIXCLOCK, 60},
+ {1280, 720, RES_1280X720_50HZ_PIXCLOCK, 50},
+ {1280, 768, RES_1280X768_50HZ_PIXCLOCK, 50},
+ {1360, 768, RES_1360X768_60HZ_PIXCLOCK, 60},
+ {1366, 768, RES_1366X768_50HZ_PIXCLOCK, 50},
+ {1366, 768, RES_1366X768_60HZ_PIXCLOCK, 60},
+ {1440, 900, RES_1440X900_60HZ_PIXCLOCK, 60},
+ {1440, 900, RES_1440X900_75HZ_PIXCLOCK, 75},
+ {1600, 900, RES_1600X900_60HZ_PIXCLOCK, 60},
+ {1600, 1024, RES_1600X1024_60HZ_PIXCLOCK, 60},
+ {1680, 1050, RES_1680X1050_60HZ_PIXCLOCK, 60},
+ {1680, 1050, RES_1680X1050_75HZ_PIXCLOCK, 75},
+ {1792, 1344, RES_1792X1344_60HZ_PIXCLOCK, 60},
+ {1856, 1392, RES_1856X1392_60HZ_PIXCLOCK, 60},
+ {1920, 1200, RES_1920X1200_60HZ_PIXCLOCK, 60},
+ {1920, 1440, RES_1920X1440_60HZ_PIXCLOCK, 60},
+ {1920, 1440, RES_1920X1440_75HZ_PIXCLOCK, 75},
+ {2048, 1536, RES_2048X1536_60HZ_PIXCLOCK, 60}
+};
+
+struct io_reg CN400_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1E, 0x0F, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */
+{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */
+{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */
+{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */
+{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */
+{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */
+{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */
+{VIACR, CR8B, 0xFF, 0x69}, /* LCD Power Sequence Control 0 */
+{VIACR, CR8C, 0xFF, 0x57}, /* LCD Power Sequence Control 1 */
+{VIACR, CR8D, 0xFF, 0x00}, /* LCD Power Sequence Control 2 */
+{VIACR, CR8E, 0xFF, 0x7B}, /* LCD Power Sequence Control 3 */
+{VIACR, CR8F, 0xFF, 0x03}, /* LCD Power Sequence Control 4 */
+{VIACR, CR90, 0xFF, 0x30}, /* LCD Power Sequence Control 5 */
+{VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00}
+};
+
+/* Video Mode Table for VT3314 chipset*/
+/* Common Setting for Video Mode */
+struct io_reg CN700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x82},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1F, 0xFF, 0x00},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR22, 0xFF, 0x1F},
+{VIASR, SR2A, 0x0F, 0x00},
+{VIASR, SR2E, 0xFF, 0xFF},
+{VIASR, SR3F, 0xFF, 0xFF},
+{VIASR, SR40, 0xF7, 0x00},
+{VIASR, CR30, 0xFF, 0x04},
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0x7F, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0xFF, 0x31},
+{VIACR, CR41, 0xFF, 0x80},
+{VIACR, CR42, 0xFF, 0x00},
+{VIACR, CR55, 0x80, 0x00},
+{VIACR, CR5D, 0x80, 0x00}, /*Horizontal Retrace Start bit[11] should be 0*/
+{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFD, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR77, 0xFF, 0x00}, /* LCD scaling Factor */
+{VIACR, CR78, 0xFF, 0x00}, /* LCD scaling Factor */
+{VIACR, CR79, 0xFF, 0x00}, /* LCD scaling Factor */
+{VIACR, CR9F, 0x03, 0x00}, /* LCD scaling Factor */
+{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */
+{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */
+{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */
+{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */
+{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */
+{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */
+{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */
+{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */
+{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */
+{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */
+{VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CR9D, 0xFF, 0x80},
+{VIACR, CR9E, 0xFF, 0x80}
+};
+
+struct io_reg KM400_ModeXregs[] = {
+ {VIASR, SR10, 0xFF, 0x01}, /* Unlock Register */
+ {VIASR, SR16, 0xFF, 0x08}, /* Display FIFO threshold Control */
+ {VIASR, SR17, 0xFF, 0x1F}, /* Display FIFO Control */
+ {VIASR, SR18, 0xFF, 0x4E}, /* GFX PREQ threshold */
+ {VIASR, SR1A, 0xFF, 0x0a}, /* GFX PREQ threshold */
+ {VIASR, SR1F, 0xFF, 0x00}, /* Memory Control 0 */
+ {VIASR, SR1B, 0xFF, 0xF0}, /* Power Management Control 0 */
+ {VIASR, SR1E, 0xFF, 0x01}, /* Power Management Control */
+ {VIASR, SR20, 0xFF, 0x00}, /* Sequencer Arbiter Control 0 */
+ {VIASR, SR21, 0xFF, 0x00}, /* Sequencer Arbiter Control 1 */
+ {VIASR, SR22, 0xFF, 0x1F}, /* Display Arbiter Control 1 */
+ {VIASR, SR2A, 0xFF, 0x00}, /* Power Management Control 5 */
+ {VIASR, SR2D, 0xFF, 0xFF}, /* Power Management Control 1 */
+ {VIASR, SR2E, 0xFF, 0xFF}, /* Power Management Control 2 */
+ {VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */
+ {VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */
+ {VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */
+ {VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */
+ {VIACR, CR33, 0xFF, 0x00},
+ {VIACR, CR55, 0x80, 0x00},
+ {VIACR, CR5D, 0x80, 0x00},
+ {VIACR, CR36, 0xFF, 0x01}, /* Power Mangement 3 */
+ {VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */
+ {VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */
+ {VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */
+ {VIACR, CR68, 0xFF, 0x67}, /* Default FIFO For IGA2 */
+ {VIACR, CR6A, 0x20, 0x20}, /* Extended FIFO On */
+ {VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */
+ {VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */
+ {VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */
+ {VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */
+ {VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */
+ {VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */
+ {VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */
+ {VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */
+ {VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */
+ {VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */
+ {VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */
+ {VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */
+ {VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */
+ {VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */
+ {VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */
+ {VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */
+ {VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */
+ {VIACR, CR8B, 0xFF, 0x2D}, /* LCD Power Sequence Control 0 */
+ {VIACR, CR8C, 0xFF, 0x2D}, /* LCD Power Sequence Control 1 */
+ {VIACR, CR8D, 0xFF, 0xC8}, /* LCD Power Sequence Control 2 */
+ {VIACR, CR8E, 0xFF, 0x36}, /* LCD Power Sequence Control 3 */
+ {VIACR, CR8F, 0xFF, 0x00}, /* LCD Power Sequence Control 4 */
+ {VIACR, CR90, 0xFF, 0x10}, /* LCD Power Sequence Control 5 */
+ {VIACR, CR91, 0xFF, 0xA0}, /* 24/12 bit LVDS Data off */
+ {VIACR, CR96, 0xFF, 0x03}, /* DVP0 ; DVP0 Clock Skew */
+ {VIACR, CR97, 0xFF, 0x03}, /* DFP high ; DFPH Clock Skew */
+ {VIACR, CR99, 0xFF, 0x03}, /* DFP low ; DFPL Clock Skew*/
+ {VIACR, CR9B, 0xFF, 0x07} /* DVI on DVP1 ; DVP1 Clock Skew*/
+};
+
+/* For VT3324: Common Setting for Video Mode */
+struct io_reg CX700_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */
+{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */
+{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */
+{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */
+{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR47, 0xC8, 0x00}, /* Clear VCK Plus. */
+{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CRA3, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */
+{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */
+{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */
+{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */
+{VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */
+{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */
+{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */
+{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */
+{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */
+{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */
+{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */
+{VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CRD2, 0xFF, 0xFF} /* TMDS/LVDS control register. */
+};
+
+/* For VT3353: Common Setting for Video Mode */
+struct io_reg VX800_ModeXregs[] = { {VIASR, SR10, 0xFF, 0x01},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+{VIASR, SR1B, 0xFF, 0xF0},
+{VIASR, SR1E, 0xFF, 0x01},
+{VIASR, SR2A, 0xFF, 0x00},
+{VIASR, SR2D, 0xFF, 0xFF}, /* VCK and LCK PLL power on. */
+{VIACR, CR0A, 0xFF, 0x1E}, /* Cursor Start */
+{VIACR, CR0B, 0xFF, 0x00}, /* Cursor End */
+{VIACR, CR0E, 0xFF, 0x00}, /* Cursor Location High */
+{VIACR, CR0F, 0xFF, 0x00}, /* Cursor Localtion Low */
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR33, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR47, 0xC8, 0x00}, /* Clear VCK Plus. */
+{VIACR, CR62, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR63, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR64, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CRA3, 0xFF, 0x00}, /* Secondary Display Starting Address */
+{VIACR, CR69, 0xFF, 0x00},
+{VIACR, CR6A, 0xFF, 0x40},
+{VIACR, CR6B, 0xFF, 0x00},
+{VIACR, CR6C, 0xFF, 0x00},
+{VIACR, CR7A, 0xFF, 0x01}, /* LCD Scaling Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02}, /* LCD Scaling Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03}, /* LCD Scaling Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04}, /* LCD Scaling Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07}, /* LCD Scaling Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Scaling Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D}, /* LCD Scaling Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13}, /* LCD Scaling Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16}, /* LCD Scaling Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19}, /* LCD Scaling Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C}, /* LCD Scaling Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D}, /* LCD Scaling Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E}, /* LCD Scaling Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F}, /* LCD Scaling Parameter 14 */
+{VIACR, CR88, 0xFF, 0x40}, /* LCD Panel Type */
+{VIACR, CR89, 0xFF, 0x00}, /* LCD Timing Control 0 */
+{VIACR, CR8A, 0xFF, 0x88}, /* LCD Timing Control 1 */
+{VIACR, CRD4, 0xFF, 0x81}, /* Second power sequence control */
+{VIACR, CR8B, 0xFF, 0x5D}, /* LCD Power Sequence Control 0 */
+{VIACR, CR8C, 0xFF, 0x2B}, /* LCD Power Sequence Control 1 */
+{VIACR, CR8D, 0xFF, 0x6F}, /* LCD Power Sequence Control 2 */
+{VIACR, CR8E, 0xFF, 0x2B}, /* LCD Power Sequence Control 3 */
+{VIACR, CR8F, 0xFF, 0x01}, /* LCD Power Sequence Control 4 */
+{VIACR, CR90, 0xFF, 0x01}, /* LCD Power Sequence Control 5 */
+{VIACR, CR91, 0xFF, 0x80}, /* 24/12 bit LVDS Data off */
+{VIACR, CR96, 0xFF, 0x00},
+{VIACR, CR97, 0xFF, 0x00},
+{VIACR, CR99, 0xFF, 0x00},
+{VIACR, CR9B, 0xFF, 0x00},
+{VIACR, CRD2, 0xFF, 0xFF} /* TMDS/LVDS control register. */
+};
+
+/* Video Mode Table */
+/* Common Setting for Video Mode */
+struct io_reg CLE266_ModeXregs[] = { {VIASR, SR1E, 0xF0, 0x00},
+{VIASR, SR2A, 0x0F, 0x00},
+{VIASR, SR15, 0x02, 0x02},
+{VIASR, SR16, 0xBF, 0x08},
+{VIASR, SR17, 0xFF, 0x1F},
+{VIASR, SR18, 0xFF, 0x4E},
+{VIASR, SR1A, 0xFB, 0x08},
+
+{VIACR, CR32, 0xFF, 0x00},
+{VIACR, CR34, 0xFF, 0x00},
+{VIACR, CR35, 0xFF, 0x00},
+{VIACR, CR36, 0x08, 0x00},
+{VIACR, CR6A, 0xFF, 0x80},
+{VIACR, CR6A, 0xFF, 0xC0},
+
+{VIACR, CR55, 0x80, 0x00},
+{VIACR, CR5D, 0x80, 0x00},
+
+{VIAGR, GR20, 0xFF, 0x00},
+{VIAGR, GR21, 0xFF, 0x00},
+{VIAGR, GR22, 0xFF, 0x00},
+ /* LCD Parameters */
+{VIACR, CR7A, 0xFF, 0x01}, /* LCD Parameter 1 */
+{VIACR, CR7B, 0xFF, 0x02}, /* LCD Parameter 2 */
+{VIACR, CR7C, 0xFF, 0x03}, /* LCD Parameter 3 */
+{VIACR, CR7D, 0xFF, 0x04}, /* LCD Parameter 4 */
+{VIACR, CR7E, 0xFF, 0x07}, /* LCD Parameter 5 */
+{VIACR, CR7F, 0xFF, 0x0A}, /* LCD Parameter 6 */
+{VIACR, CR80, 0xFF, 0x0D}, /* LCD Parameter 7 */
+{VIACR, CR81, 0xFF, 0x13}, /* LCD Parameter 8 */
+{VIACR, CR82, 0xFF, 0x16}, /* LCD Parameter 9 */
+{VIACR, CR83, 0xFF, 0x19}, /* LCD Parameter 10 */
+{VIACR, CR84, 0xFF, 0x1C}, /* LCD Parameter 11 */
+{VIACR, CR85, 0xFF, 0x1D}, /* LCD Parameter 12 */
+{VIACR, CR86, 0xFF, 0x1E}, /* LCD Parameter 13 */
+{VIACR, CR87, 0xFF, 0x1F}, /* LCD Parameter 14 */
+
+};
+
+/* Mode:1024X768 */
+struct io_reg PM1024x768[] = { {VIASR, 0x16, 0xBF, 0x0C},
+{VIASR, 0x18, 0xFF, 0x4C}
+};
+
+struct patch_table res_patch_table[] = {
+ {VIA_RES_1024X768, ARRAY_SIZE(PM1024x768), PM1024x768}
+};
+
+/* struct VPITTable {
+ unsigned char Misc;
+ unsigned char SR[StdSR];
+ unsigned char CR[StdCR];
+ unsigned char GR[StdGR];
+ unsigned char AR[StdAR];
+ };*/
+
+struct VPITTable VPIT = {
+ /* Msic */
+ 0xC7,
+ /* Sequencer */
+ {0x01, 0x0F, 0x00, 0x0E},
+ /* Graphic Controller */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F, 0xFF},
+ /* Attribute Controller */
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x01, 0x00, 0x0F, 0x00}
+};
+
+/********************/
+/* Mode Table */
+/********************/
+
+/* 480x640 */
+struct crt_mode_table CRTM480x640[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_25_175M, M480X640_R60_HSP, M480X640_R60_VSP,
+ {624, 480, 480, 144, 504, 48, 663, 640, 640, 23, 641, 3} } /* GTF*/
+};
+
+/* 640x480*/
+struct crt_mode_table CRTM640x480[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_25_175M, M640X480_R60_HSP, M640X480_R60_VSP,
+ {800, 640, 648, 144, 656, 96, 525, 480, 480, 45, 490, 2} },
+ {REFRESH_75, CLK_31_500M, M640X480_R75_HSP, M640X480_R75_VSP,
+ {840, 640, 640, 200, 656, 64, 500, 480, 480, 20, 481, 3} },
+ {REFRESH_85, CLK_36_000M, M640X480_R85_HSP, M640X480_R85_VSP,
+ {832, 640, 640, 192, 696, 56, 509, 480, 480, 29, 481, 3} },
+ {REFRESH_100, CLK_43_163M, M640X480_R100_HSP, M640X480_R100_VSP,
+ {848, 640, 640, 208, 680, 64, 509, 480, 480, 29, 481, 3} }, /*GTF*/
+ {REFRESH_120, CLK_52_406M, M640X480_R120_HSP,
+ M640X480_R120_VSP,
+ {848, 640, 640, 208, 680, 64, 515, 480, 480, 35, 481,
+ 3} } /*GTF*/
+};
+
+/*720x480 (GTF)*/
+struct crt_mode_table CRTM720x480[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_26_880M, M720X480_R60_HSP, M720X480_R60_VSP,
+ {896, 720, 720, 176, 736, 72, 497, 480, 480, 17, 481, 3} }
+
+};
+
+/*720x576 (GTF)*/
+struct crt_mode_table CRTM720x576[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_32_668M, M720X576_R60_HSP, M720X576_R60_VSP,
+ {912, 720, 720, 192, 744, 72, 597, 576, 576, 21, 577, 3} }
+};
+
+/* 800x480 (CVT) */
+struct crt_mode_table CRTM800x480[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_29_581M, M800X480_R60_HSP, M800X480_R60_VSP,
+ {992, 800, 800, 192, 824, 72, 500, 480, 480, 20, 483, 7} }
+};
+
+/* 800x600*/
+struct crt_mode_table CRTM800x600[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_40_000M, M800X600_R60_HSP, M800X600_R60_VSP,
+ {1056, 800, 800, 256, 840, 128, 628, 600, 600, 28, 601, 4} },
+ {REFRESH_75, CLK_49_500M, M800X600_R75_HSP, M800X600_R75_VSP,
+ {1056, 800, 800, 256, 816, 80, 625, 600, 600, 25, 601, 3} },
+ {REFRESH_85, CLK_56_250M, M800X600_R85_HSP, M800X600_R85_VSP,
+ {1048, 800, 800, 248, 832, 64, 631, 600, 600, 31, 601, 3} },
+ {REFRESH_100, CLK_68_179M, M800X600_R100_HSP, M800X600_R100_VSP,
+ {1072, 800, 800, 272, 848, 88, 636, 600, 600, 36, 601, 3} },
+ {REFRESH_120, CLK_83_950M, M800X600_R120_HSP,
+ M800X600_R120_VSP,
+ {1088, 800, 800, 288, 856, 88, 643, 600, 600, 43, 601,
+ 3} }
+};
+
+/* 848x480 (CVT) */
+struct crt_mode_table CRTM848x480[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_31_500M, M848X480_R60_HSP, M848X480_R60_VSP,
+ {1056, 848, 848, 208, 872, 80, 500, 480, 480, 20, 483, 5} }
+};
+
+/*856x480 (GTF) convert to 852x480*/
+struct crt_mode_table CRTM852x480[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_31_728M, M852X480_R60_HSP, M852X480_R60_VSP,
+ {1064, 856, 856, 208, 872, 88, 497, 480, 480, 17, 481, 3} }
+};
+
+/*1024x512 (GTF)*/
+struct crt_mode_table CRTM1024x512[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_41_291M, M1024X512_R60_HSP, M1024X512_R60_VSP,
+ {1296, 1024, 1024, 272, 1056, 104, 531, 512, 512, 19, 513, 3} }
+
+};
+
+/* 1024x600*/
+struct crt_mode_table CRTM1024x600[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_48_875M, M1024X600_R60_HSP, M1024X600_R60_VSP,
+ {1312, 1024, 1024, 288, 1064, 104, 622, 600, 600, 22, 601, 3} },
+};
+
+/* 1024x768*/
+struct crt_mode_table CRTM1024x768[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_65_000M, M1024X768_R60_HSP, M1024X768_R60_VSP,
+ {1344, 1024, 1024, 320, 1048, 136, 806, 768, 768, 38, 771, 6} },
+ {REFRESH_75, CLK_78_750M, M1024X768_R75_HSP, M1024X768_R75_VSP,
+ {1312, 1024, 1024, 288, 1040, 96, 800, 768, 768, 32, 769, 3} },
+ {REFRESH_85, CLK_94_500M, M1024X768_R85_HSP, M1024X768_R85_VSP,
+ {1376, 1024, 1024, 352, 1072, 96, 808, 768, 768, 40, 769, 3} },
+ {REFRESH_100, CLK_113_309M, M1024X768_R100_HSP, M1024X768_R100_VSP,
+ {1392, 1024, 1024, 368, 1096, 112, 814, 768, 768, 46, 769, 3} }
+};
+
+/* 1152x864*/
+struct crt_mode_table CRTM1152x864[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_75, CLK_108_000M, M1152X864_R75_HSP, M1152X864_R75_VSP,
+ {1600, 1152, 1152, 448, 1216, 128, 900, 864, 864, 36, 865, 3} }
+
+};
+
+/* 1280x720 (HDMI 720P)*/
+struct crt_mode_table CRTM1280x720[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_74_481M, M1280X720_R60_HSP, M1280X720_R60_VSP,
+ {1648, 1280, 1280, 368, 1392, 40, 750, 720, 720, 30, 725, 5} },
+ {REFRESH_50, CLK_60_466M, M1280X720_R50_HSP, M1280X720_R50_VSP,
+ {1632, 1280, 1280, 352, 1328, 128, 741, 720, 720, 21, 721, 3} }
+};
+
+/*1280x768 (GTF)*/
+struct crt_mode_table CRTM1280x768[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_80_136M, M1280X768_R60_HSP, M1280X768_R60_VSP,
+ {1680, 1280, 1280, 400, 1344, 136, 795, 768, 768, 27, 769, 3} },
+ {REFRESH_50, CLK_65_178M, M1280X768_R50_HSP, M1280X768_R50_VSP,
+ {1648, 1280, 1280, 368, 1336, 128, 791, 768, 768, 23, 769, 3} }
+};
+
+/* 1280x800 (CVT) */
+struct crt_mode_table CRTM1280x800[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_83_375M, M1280X800_R60_HSP, M1280X800_R60_VSP,
+ {1680, 1280, 1280, 400, 1352, 128, 831, 800, 800, 31, 803, 6} }
+};
+
+/*1280x960*/
+struct crt_mode_table CRTM1280x960[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_108_000M, M1280X960_R60_HSP, M1280X960_R60_VSP,
+ {1800, 1280, 1280, 520, 1376, 112, 1000, 960, 960, 40, 961, 3} }
+};
+
+/* 1280x1024*/
+struct crt_mode_table CRTM1280x1024[] = {
+ /*r_rate,vclk,,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_108_000M, M1280X1024_R60_HSP, M1280X1024_R60_VSP,
+ {1688, 1280, 1280, 408, 1328, 112, 1066, 1024, 1024, 42, 1025,
+ 3} },
+ {REFRESH_75, CLK_135_000M, M1280X1024_R75_HSP, M1280X1024_R75_VSP,
+ {1688, 1280, 1280, 408, 1296, 144, 1066, 1024, 1024, 42, 1025,
+ 3} },
+ {REFRESH_85, CLK_157_500M, M1280X1024_R85_HSP, M1280X1024_R85_VSP,
+ {1728, 1280, 1280, 448, 1344, 160, 1072, 1024, 1024, 48, 1025, 3} }
+};
+
+/* 1368x768 (GTF) */
+struct crt_mode_table CRTM1368x768[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP,
+ {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} }
+};
+
+/*1440x1050 (GTF)*/
+struct crt_mode_table CRTM1440x1050[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_125_104M, M1440X1050_R60_HSP, M1440X1050_R60_VSP,
+ {1936, 1440, 1440, 496, 1536, 152, 1077, 1040, 1040, 37, 1041, 3} }
+};
+
+/* 1600x1200*/
+struct crt_mode_table CRTM1600x1200[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_162_000M, M1600X1200_R60_HSP, M1600X1200_R60_VSP,
+ {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201,
+ 3} },
+ {REFRESH_75, CLK_202_500M, M1600X1200_R75_HSP, M1600X1200_R75_VSP,
+ {2160, 1600, 1600, 560, 1664, 192, 1250, 1200, 1200, 50, 1201, 3} }
+
+};
+
+/* 1680x1050 (CVT) */
+struct crt_mode_table CRTM1680x1050[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_146_760M, M1680x1050_R60_HSP, M1680x1050_R60_VSP,
+ {2240, 1680, 1680, 560, 1784, 176, 1089, 1050, 1050, 39, 1053,
+ 6} },
+ {REFRESH_75, CLK_187_000M, M1680x1050_R75_HSP, M1680x1050_R75_VSP,
+ {2272, 1680, 1680, 592, 1800, 176, 1099, 1050, 1050, 49, 1053, 6} }
+};
+
+/* 1680x1050 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1680x1050_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_119_000M, M1680x1050_RB_R60_HSP,
+ M1680x1050_RB_R60_VSP,
+ {1840, 1680, 1680, 160, 1728, 32, 1080, 1050, 1050, 30, 1053, 6} }
+};
+
+/* 1920x1080 (CVT)*/
+struct crt_mode_table CRTM1920x1080[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_172_798M, M1920X1080_R60_HSP, M1920X1080_R60_VSP,
+ {2576, 1920, 1920, 656, 2048, 200, 1120, 1080, 1080, 40, 1083, 5} }
+};
+
+/* 1920x1080 (CVT with Reduce Blanking) */
+struct crt_mode_table CRTM1920x1080_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_138_400M, M1920X1080_RB_R60_HSP,
+ M1920X1080_RB_R60_VSP,
+ {2080, 1920, 1920, 160, 1968, 32, 1111, 1080, 1080, 31, 1083, 5} }
+};
+
+/* 1920x1440*/
+struct crt_mode_table CRTM1920x1440[] = {
+ /*r_rate,vclk,hsp,vsp */
+ /*HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_234_000M, M1920X1440_R60_HSP, M1920X1440_R60_VSP,
+ {2600, 1920, 1920, 680, 2048, 208, 1500, 1440, 1440, 60, 1441,
+ 3} },
+ {REFRESH_75, CLK_297_500M, M1920X1440_R75_HSP, M1920X1440_R75_VSP,
+ {2640, 1920, 1920, 720, 2064, 224, 1500, 1440, 1440, 60, 1441, 3} }
+};
+
+/* 1400x1050 (CVT) */
+struct crt_mode_table CRTM1400x1050[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_121_750M, M1400X1050_R60_HSP, M1400X1050_R60_VSP,
+ {1864, 1400, 1400, 464, 1488, 144, 1089, 1050, 1050, 39, 1053,
+ 4} },
+ {REFRESH_75, CLK_156_000M, M1400X1050_R75_HSP, M1400X1050_R75_VSP,
+ {1896, 1400, 1400, 496, 1504, 144, 1099, 1050, 1050, 49, 1053, 4} }
+};
+
+/* 1400x1050 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1400x1050_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_101_000M, M1400X1050_RB_R60_HSP,
+ M1400X1050_RB_R60_VSP,
+ {1560, 1400, 1400, 160, 1448, 32, 1080, 1050, 1050, 30, 1053, 4} }
+};
+
+/* 960x600 (CVT) */
+struct crt_mode_table CRTM960x600[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_45_250M, M960X600_R60_HSP, M960X600_R60_VSP,
+ {1216, 960, 960, 256, 992, 96, 624, 600, 600, 24, 603, 6} }
+};
+
+/* 1000x600 (GTF) */
+struct crt_mode_table CRTM1000x600[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_48_000M, M1000X600_R60_HSP, M1000X600_R60_VSP,
+ {1288, 1000, 1000, 288, 1040, 104, 622, 600, 600, 22, 601, 3} }
+};
+
+/* 1024x576 (GTF) */
+struct crt_mode_table CRTM1024x576[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_46_996M, M1024X576_R60_HSP, M1024X576_R60_VSP,
+ {1312, 1024, 1024, 288, 1064, 104, 597, 576, 576, 21, 577, 3} }
+};
+
+/* 1088x612 (CVT) */
+struct crt_mode_table CRTM1088x612[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_52_977M, M1088X612_R60_HSP, M1088X612_R60_VSP,
+ {1392, 1088, 1088, 304, 1136, 104, 636, 612, 612, 24, 615, 5} }
+};
+
+/* 1152x720 (CVT) */
+struct crt_mode_table CRTM1152x720[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_66_750M, M1152X720_R60_HSP, M1152X720_R60_VSP,
+ {1488, 1152, 1152, 336, 1208, 112, 748, 720, 720, 28, 723, 6} }
+};
+
+/* 1200x720 (GTF) */
+struct crt_mode_table CRTM1200x720[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_70_159M, M1200X720_R60_HSP, M1200X720_R60_VSP,
+ {1568, 1200, 1200, 368, 1256, 128, 746, 720, 720, 26, 721, 3} }
+};
+
+/* 1280x600 (GTF) */
+struct crt_mode_table CRTM1280x600[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_61_500M, M1280x600_R60_HSP, M1280x600_R60_VSP,
+ {1648, 1280, 1280, 368, 1336, 128, 622, 600, 600, 22, 601, 3} }
+};
+
+/* 1360x768 (CVT) */
+struct crt_mode_table CRTM1360x768[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_84_750M, M1360X768_R60_HSP, M1360X768_R60_VSP,
+ {1776, 1360, 1360, 416, 1432, 136, 798, 768, 768, 30, 771, 5} }
+};
+
+/* 1360x768 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1360x768_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_72_000M, M1360X768_RB_R60_HSP,
+ M1360X768_RB_R60_VSP,
+ {1520, 1360, 1360, 160, 1408, 32, 790, 768, 768, 22, 771, 5} }
+};
+
+/* 1366x768 (GTF) */
+struct crt_mode_table CRTM1366x768[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_85_860M, M1368X768_R60_HSP, M1368X768_R60_VSP,
+ {1800, 1368, 1368, 432, 1440, 144, 795, 768, 768, 27, 769, 3} },
+ {REFRESH_50, CLK_69_924M, M1368X768_R50_HSP, M1368X768_R50_VSP,
+ {1768, 1368, 1368, 400, 1424, 144, 791, 768, 768, 23, 769, 3} }
+};
+
+/* 1440x900 (CVT) */
+struct crt_mode_table CRTM1440x900[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_106_500M, M1440X900_R60_HSP, M1440X900_R60_VSP,
+ {1904, 1440, 1440, 464, 1520, 152, 934, 900, 900, 34, 903, 6} },
+ {REFRESH_75, CLK_136_700M, M1440X900_R75_HSP, M1440X900_R75_VSP,
+ {1936, 1440, 1440, 496, 1536, 152, 942, 900, 900, 42, 903, 6} }
+};
+
+/* 1440x900 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1440x900_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_88_750M, M1440X900_RB_R60_HSP,
+ M1440X900_RB_R60_VSP,
+ {1600, 1440, 1440, 160, 1488, 32, 926, 900, 900, 26, 903, 6} }
+};
+
+/* 1600x900 (CVT) */
+struct crt_mode_table CRTM1600x900[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_118_840M, M1600X900_R60_HSP, M1600X900_R60_VSP,
+ {2112, 1600, 1600, 512, 1688, 168, 934, 900, 900, 34, 903, 5} }
+};
+
+/* 1600x900 (CVT Reduce Blanking) */
+struct crt_mode_table CRTM1600x900_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_97_750M, M1600X900_RB_R60_HSP,
+ M1600X900_RB_R60_VSP,
+ {1760, 1600, 1600, 160, 1648, 32, 926, 900, 900, 26, 903, 5} }
+};
+
+/* 1600x1024 (GTF) */
+struct crt_mode_table CRTM1600x1024[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_136_700M, M1600X1024_R60_HSP, M1600X1024_R60_VSP,
+ {2144, 1600, 1600, 544, 1704, 168, 1060, 1024, 1024, 36, 1025, 3} }
+};
+
+/* 1792x1344 (DMT) */
+struct crt_mode_table CRTM1792x1344[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_204_000M, M1792x1344_R60_HSP, M1792x1344_R60_VSP,
+ {2448, 1792, 1792, 656, 1920, 200, 1394, 1344, 1344, 50, 1345, 3} }
+};
+
+/* 1856x1392 (DMT) */
+struct crt_mode_table CRTM1856x1392[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_218_500M, M1856x1392_R60_HSP, M1856x1392_R60_VSP,
+ {2528, 1856, 1856, 672, 1952, 224, 1439, 1392, 1392, 47, 1393, 3} }
+};
+
+/* 1920x1200 (CVT) */
+struct crt_mode_table CRTM1920x1200[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_193_295M, M1920X1200_R60_HSP, M1920X1200_R60_VSP,
+ {2592, 1920, 1920, 672, 2056, 200, 1245, 1200, 1200, 45, 1203, 6} }
+};
+
+/* 1920x1200 (CVT with Reduce Blanking) */
+struct crt_mode_table CRTM1920x1200_RB[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_153_920M, M1920X1200_RB_R60_HSP,
+ M1920X1200_RB_R60_VSP,
+ {2080, 1920, 1920, 160, 1968, 32, 1235, 1200, 1200, 35, 1203, 6} }
+};
+
+/* 2048x1536 (CVT) */
+struct crt_mode_table CRTM2048x1536[] = {
+ /* r_rate, vclk, hsp, vsp */
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {REFRESH_60, CLK_267_250M, M2048x1536_R60_HSP, M2048x1536_R60_VSP,
+ {2800, 2048, 2048, 752, 2200, 224, 1592, 1536, 1536, 56, 1539, 4} }
+};
+
+/* Video Mode Table */
+/* struct VideoModeTable {*/
+/* int ModeIndex;*/
+/* struct crt_mode_table *crtc;*/
+/* int mode_array;*/
+/* };*/
+struct VideoModeTable CLE266Modes[] = {
+ /* Display : 480x640 (GTF) */
+ {VIA_RES_480X640, CRTM480x640, ARRAY_SIZE(CRTM480x640)},
+
+ /* Display : 640x480 */
+ {VIA_RES_640X480, CRTM640x480, ARRAY_SIZE(CRTM640x480)},
+
+ /* Display : 720x480 (GTF) */
+ {VIA_RES_720X480, CRTM720x480, ARRAY_SIZE(CRTM720x480)},
+
+ /* Display : 720x576 (GTF) */
+ {VIA_RES_720X576, CRTM720x576, ARRAY_SIZE(CRTM720x576)},
+
+ /* Display : 800x600 */
+ {VIA_RES_800X600, CRTM800x600, ARRAY_SIZE(CRTM800x600)},
+
+ /* Display : 800x480 (CVT) */
+ {VIA_RES_800X480, CRTM800x480, ARRAY_SIZE(CRTM800x480)},
+
+ /* Display : 848x480 (CVT) */
+ {VIA_RES_848X480, CRTM848x480, ARRAY_SIZE(CRTM848x480)},
+
+ /* Display : 852x480 (GTF) */
+ {VIA_RES_856X480, CRTM852x480, ARRAY_SIZE(CRTM852x480)},
+
+ /* Display : 1024x512 (GTF) */
+ {VIA_RES_1024X512, CRTM1024x512, ARRAY_SIZE(CRTM1024x512)},
+
+ /* Display : 1024x600 */
+ {VIA_RES_1024X600, CRTM1024x600, ARRAY_SIZE(CRTM1024x600)},
+
+ /* Display : 1024x576 (GTF) */
+ /*{ VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)}, */
+
+ /* Display : 1024x768 */
+ {VIA_RES_1024X768, CRTM1024x768, ARRAY_SIZE(CRTM1024x768)},
+
+ /* Display : 1152x864 */
+ {VIA_RES_1152X864, CRTM1152x864, ARRAY_SIZE(CRTM1152x864)},
+
+ /* Display : 1280x768 (GTF) */
+ {VIA_RES_1280X768, CRTM1280x768, ARRAY_SIZE(CRTM1280x768)},
+
+ /* Display : 960x600 (CVT) */
+ {VIA_RES_960X600, CRTM960x600, ARRAY_SIZE(CRTM960x600)},
+
+ /* Display : 1000x600 (GTF) */
+ {VIA_RES_1000X600, CRTM1000x600, ARRAY_SIZE(CRTM1000x600)},
+
+ /* Display : 1024x576 (GTF) */
+ {VIA_RES_1024X576, CRTM1024x576, ARRAY_SIZE(CRTM1024x576)},
+
+ /* Display : 1088x612 (GTF) */
+ {VIA_RES_1088X612, CRTM1088x612, ARRAY_SIZE(CRTM1088x612)},
+
+ /* Display : 1152x720 (CVT) */
+ {VIA_RES_1152X720, CRTM1152x720, ARRAY_SIZE(CRTM1152x720)},
+
+ /* Display : 1200x720 (GTF) */
+ {VIA_RES_1200X720, CRTM1200x720, ARRAY_SIZE(CRTM1200x720)},
+
+ /* Display : 1280x600 (GTF) */
+ {VIA_RES_1280X600, CRTM1280x600, ARRAY_SIZE(CRTM1280x600)},
+
+ /* Display : 1280x800 (CVT) */
+ {VIA_RES_1280X800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)},
+
+ /* Display : 1280x800 (GTF) */
+ /*{ M1280x800, CRTM1280x800, ARRAY_SIZE(CRTM1280x800)}, */
+
+ /* Display : 1280x960 */
+ {VIA_RES_1280X960, CRTM1280x960, ARRAY_SIZE(CRTM1280x960)},
+
+ /* Display : 1280x1024 */
+ {VIA_RES_1280X1024, CRTM1280x1024, ARRAY_SIZE(CRTM1280x1024)},
+
+ /* Display : 1360x768 (CVT) */
+ {VIA_RES_1360X768, CRTM1360x768, ARRAY_SIZE(CRTM1360x768)},
+
+ /* Display : 1360x768 (CVT Reduce Blanking) */
+ {VIA_RES_1360X768_RB, CRTM1360x768_RB,
+ ARRAY_SIZE(CRTM1360x768_RB)},
+
+ /* Display : 1366x768 */
+ {VIA_RES_1366X768, CRTM1366x768, ARRAY_SIZE(CRTM1366x768)},
+
+ /* Display : 1368x768 (GTF) */
+ /*{ M1368x768,CRTM1368x768,ARRAY_SIZE(CRTM1368x768)}, */
+ /* Display : 1368x768 (GTF) */
+ {VIA_RES_1368X768, CRTM1368x768, ARRAY_SIZE(CRTM1368x768)},
+
+ /* Display : 1440x900 (CVT) */
+ {VIA_RES_1440X900, CRTM1440x900, ARRAY_SIZE(CRTM1440x900)},
+
+ /* Display : 1440x900 (CVT Reduce Blanking) */
+ {VIA_RES_1440X900_RB, CRTM1440x900_RB,
+ ARRAY_SIZE(CRTM1440x900_RB)},
+
+ /* Display : 1440x1050 (GTF) */
+ {VIA_RES_1440X1050, CRTM1440x1050, ARRAY_SIZE(CRTM1440x1050)},
+
+ /* Display : 1400x1050 (CVT Reduce Blanking) */
+ {VIA_RES_1400X1050_RB, CRTM1400x1050_RB,
+ ARRAY_SIZE(CRTM1400x1050_RB)},
+
+ /* Display : 1600x900 (CVT) */
+ {VIA_RES_1600X900, CRTM1600x900, ARRAY_SIZE(CRTM1600x900)},
+
+ /* Display : 1600x900 (CVT Reduce Blanking) */
+ {VIA_RES_1600X900_RB, CRTM1600x900_RB,
+ ARRAY_SIZE(CRTM1600x900_RB)},
+
+ /* Display : 1600x1024 (GTF) */
+ {VIA_RES_1600X1024, CRTM1600x1024, ARRAY_SIZE(CRTM1600x1024)},
+
+ /* Display : 1600x1200 */
+ {VIA_RES_1600X1200, CRTM1600x1200, ARRAY_SIZE(CRTM1600x1200)},
+
+ /* Display : 1680x1050 (CVT) */
+ {VIA_RES_1680X1050, CRTM1680x1050, ARRAY_SIZE(CRTM1680x1050)},
+
+ /* Display : 1680x1050 (CVT Reduce Blanking) */
+ {VIA_RES_1680X1050_RB, CRTM1680x1050_RB,
+ ARRAY_SIZE(CRTM1680x1050_RB)},
+
+ /* Display : 1792x1344 (DMT) */
+ {VIA_RES_1792X1344, CRTM1792x1344, ARRAY_SIZE(CRTM1792x1344)},
+
+ /* Display : 1856x1392 (DMT) */
+ {VIA_RES_1856X1392, CRTM1856x1392, ARRAY_SIZE(CRTM1856x1392)},
+
+ /* Display : 1920x1440 */
+ {VIA_RES_1920X1440, CRTM1920x1440, ARRAY_SIZE(CRTM1920x1440)},
+
+ /* Display : 2048x1536 */
+ {VIA_RES_2048X1536, CRTM2048x1536, ARRAY_SIZE(CRTM2048x1536)},
+
+ /* Display : 1280x720 */
+ {VIA_RES_1280X720, CRTM1280x720, ARRAY_SIZE(CRTM1280x720)},
+
+ /* Display : 1920x1080 (CVT) */
+ {VIA_RES_1920X1080, CRTM1920x1080, ARRAY_SIZE(CRTM1920x1080)},
+
+ /* Display : 1920x1080 (CVT Reduce Blanking) */
+ {VIA_RES_1920X1080_RB, CRTM1920x1080_RB,
+ ARRAY_SIZE(CRTM1920x1080_RB)},
+
+ /* Display : 1920x1200 (CVT) */
+ {VIA_RES_1920X1200, CRTM1920x1200, ARRAY_SIZE(CRTM1920x1200)},
+
+ /* Display : 1920x1200 (CVT Reduce Blanking) */
+ {VIA_RES_1920X1200_RB, CRTM1920x1200_RB,
+ ARRAY_SIZE(CRTM1920x1200_RB)},
+
+ /* Display : 1400x1050 (CVT) */
+ {VIA_RES_1400X1050, CRTM1400x1050, ARRAY_SIZE(CRTM1400x1050)}
+};
+struct crt_mode_table CEAM1280x720[] = {
+ {REFRESH_60, CLK_74_270M, M1280X720_CEA_R60_HSP,
+ M1280X720_CEA_R60_VSP,
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {1650, 1280, 1280, 370, 1390, 40, 750, 720, 720, 30, 725, 5} }
+};
+struct crt_mode_table CEAM1920x1080[] = {
+ {REFRESH_60, CLK_148_500M, M1920X1080_CEA_R60_HSP,
+ M1920X1080_CEA_R60_VSP,
+ /* HT, HA, HBS, HBE, HSS, HSE, VT, VA, VBS, VBE, VSS, VSE */
+ {2200, 1920, 1920, 300, 2008, 44, 1125, 1080, 1080, 45, 1084, 5} }
+};
+struct VideoModeTable CEA_HDMI_Modes[] = {
+ /* Display : 1280x720 */
+ {VIA_RES_1280X720, CEAM1280x720, ARRAY_SIZE(CEAM1280x720)},
+ {VIA_RES_1920X1080, CEAM1920x1080, ARRAY_SIZE(CEAM1920x1080)}
+};
diff --git a/drivers/video/via/viamode.h b/drivers/video/via/viamode.h
new file mode 100644
index 00000000000..1a5de50a23a
--- /dev/null
+++ b/drivers/video/via/viamode.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 __VIAMODE_H__
+#define __VIAMODE_H__
+
+#include "global.h"
+
+struct VPITTable {
+ unsigned char Misc;
+ unsigned char SR[StdSR];
+ unsigned char GR[StdGR];
+ unsigned char AR[StdAR];
+};
+
+struct VideoModeTable {
+ int ModeIndex;
+ struct crt_mode_table *crtc;
+ int mode_array;
+};
+
+struct patch_table {
+ int mode_index;
+ int table_length;
+ struct io_reg *io_reg_table;
+};
+
+struct res_map_refresh {
+ int hres;
+ int vres;
+ int pixclock;
+ int vmode_refresh;
+};
+
+#define NUM_TOTAL_RES_MAP_REFRESH ARRAY_SIZE(res_map_refresh_tbl)
+#define NUM_TOTAL_CEA_MODES ARRAY_SIZE(CEA_HDMI_Modes)
+#define NUM_TOTAL_CN400_ModeXregs ARRAY_SIZE(CN400_ModeXregs)
+#define NUM_TOTAL_CN700_ModeXregs ARRAY_SIZE(CN700_ModeXregs)
+#define NUM_TOTAL_KM400_ModeXregs ARRAY_SIZE(KM400_ModeXregs)
+#define NUM_TOTAL_CX700_ModeXregs ARRAY_SIZE(CX700_ModeXregs)
+#define NUM_TOTAL_VX800_ModeXregs ARRAY_SIZE(VX800_ModeXregs)
+#define NUM_TOTAL_CLE266_ModeXregs ARRAY_SIZE(CLE266_ModeXregs)
+#define NUM_TOTAL_PATCH_MODE ARRAY_SIZE(res_patch_table)
+#define NUM_TOTAL_MODETABLE ARRAY_SIZE(CLE266Modes)
+
+/********************/
+/* Mode Table */
+/********************/
+
+/* 480x640 */
+extern struct crt_mode_table CRTM480x640[1];
+/* 640x480*/
+extern struct crt_mode_table CRTM640x480[5];
+/*720x480 (GTF)*/
+extern struct crt_mode_table CRTM720x480[1];
+/*720x576 (GTF)*/
+extern struct crt_mode_table CRTM720x576[1];
+/* 800x480 (CVT) */
+extern struct crt_mode_table CRTM800x480[1];
+/* 800x600*/
+extern struct crt_mode_table CRTM800x600[5];
+/* 848x480 (CVT) */
+extern struct crt_mode_table CRTM848x480[1];
+/*856x480 (GTF) convert to 852x480*/
+extern struct crt_mode_table CRTM852x480[1];
+/*1024x512 (GTF)*/
+extern struct crt_mode_table CRTM1024x512[1];
+/* 1024x600*/
+extern struct crt_mode_table CRTM1024x600[1];
+/* 1024x768*/
+extern struct crt_mode_table CRTM1024x768[4];
+/* 1152x864*/
+extern struct crt_mode_table CRTM1152x864[1];
+/* 1280x720 (HDMI 720P)*/
+extern struct crt_mode_table CRTM1280x720[2];
+/*1280x768 (GTF)*/
+extern struct crt_mode_table CRTM1280x768[2];
+/* 1280x800 (CVT) */
+extern struct crt_mode_table CRTM1280x800[1];
+/*1280x960*/
+extern struct crt_mode_table CRTM1280x960[1];
+/* 1280x1024*/
+extern struct crt_mode_table CRTM1280x1024[3];
+/* 1368x768 (GTF) */
+extern struct crt_mode_table CRTM1368x768[1];
+/*1440x1050 (GTF)*/
+extern struct crt_mode_table CRTM1440x1050[1];
+/* 1600x1200*/
+extern struct crt_mode_table CRTM1600x1200[2];
+/* 1680x1050 (CVT) */
+extern struct crt_mode_table CRTM1680x1050[2];
+/* 1680x1050 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1680x1050_RB[1];
+/* 1920x1080 (CVT)*/
+extern struct crt_mode_table CRTM1920x1080[1];
+/* 1920x1080 (CVT with Reduce Blanking) */
+extern struct crt_mode_table CRTM1920x1080_RB[1];
+/* 1920x1440*/
+extern struct crt_mode_table CRTM1920x1440[2];
+/* 1400x1050 (CVT) */
+extern struct crt_mode_table CRTM1400x1050[2];
+/* 1400x1050 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1400x1050_RB[1];
+/* 960x600 (CVT) */
+extern struct crt_mode_table CRTM960x600[1];
+/* 1000x600 (GTF) */
+extern struct crt_mode_table CRTM1000x600[1];
+/* 1024x576 (GTF) */
+extern struct crt_mode_table CRTM1024x576[1];
+/* 1088x612 (CVT) */
+extern struct crt_mode_table CRTM1088x612[1];
+/* 1152x720 (CVT) */
+extern struct crt_mode_table CRTM1152x720[1];
+/* 1200x720 (GTF) */
+extern struct crt_mode_table CRTM1200x720[1];
+/* 1280x600 (GTF) */
+extern struct crt_mode_table CRTM1280x600[1];
+/* 1360x768 (CVT) */
+extern struct crt_mode_table CRTM1360x768[1];
+/* 1360x768 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1360x768_RB[1];
+/* 1366x768 (GTF) */
+extern struct crt_mode_table CRTM1366x768[2];
+/* 1440x900 (CVT) */
+extern struct crt_mode_table CRTM1440x900[2];
+/* 1440x900 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1440x900_RB[1];
+/* 1600x900 (CVT) */
+extern struct crt_mode_table CRTM1600x900[1];
+/* 1600x900 (CVT Reduce Blanking) */
+extern struct crt_mode_table CRTM1600x900_RB[1];
+/* 1600x1024 (GTF) */
+extern struct crt_mode_table CRTM1600x1024[1];
+/* 1792x1344 (DMT) */
+extern struct crt_mode_table CRTM1792x1344[1];
+/* 1856x1392 (DMT) */
+extern struct crt_mode_table CRTM1856x1392[1];
+/* 1920x1200 (CVT) */
+extern struct crt_mode_table CRTM1920x1200[1];
+/* 1920x1200 (CVT with Reduce Blanking) */
+extern struct crt_mode_table CRTM1920x1200_RB[1];
+/* 2048x1536 (CVT) */
+extern struct crt_mode_table CRTM2048x1536[1];
+extern struct VideoModeTable CLE266Modes[47];
+extern struct crt_mode_table CEAM1280x720[1];
+extern struct crt_mode_table CEAM1920x1080[1];
+extern struct VideoModeTable CEA_HDMI_Modes[2];
+
+extern struct res_map_refresh res_map_refresh_tbl[61];
+extern struct io_reg CN400_ModeXregs[52];
+extern struct io_reg CN700_ModeXregs[66];
+extern struct io_reg KM400_ModeXregs[55];
+extern struct io_reg CX700_ModeXregs[58];
+extern struct io_reg VX800_ModeXregs[58];
+extern struct io_reg CLE266_ModeXregs[32];
+extern struct io_reg PM1024x768[2];
+extern struct patch_table res_patch_table[1];
+extern struct VPITTable VPIT;
+#endif /* __VIAMODE_H__ */
diff --git a/drivers/video/via/vt1636.c b/drivers/video/via/vt1636.c
new file mode 100644
index 00000000000..322a9f99355
--- /dev/null
+++ b/drivers/video/via/vt1636.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 "global.h"
+
+u8 viafb_gpio_i2c_read_lvds(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info,
+ u8 index)
+{
+ u8 data;
+
+ viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
+ viafb_i2c_readbyte(plvds_chip_info->lvds_chip_slave_addr, index, &data);
+
+ return data;
+}
+
+void viafb_gpio_i2c_write_mask_lvds(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information
+ *plvds_chip_info, struct IODATA io_data)
+{
+ int index, data;
+
+ viaparinfo->i2c_stuff.i2c_port = plvds_chip_info->i2c_port;
+
+ index = io_data.Index;
+ data = viafb_gpio_i2c_read_lvds(plvds_setting_info, plvds_chip_info,
+ index);
+ data = (data & (~io_data.Mask)) | io_data.Data;
+
+ viafb_i2c_writebyte(plvds_chip_info->lvds_chip_slave_addr, index, data);
+}
+
+void viafb_init_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info)
+{
+ int reg_num, i;
+
+ /* Common settings: */
+ reg_num = ARRAY_SIZE(COMMON_INIT_TBL_VT1636);
+
+ for (i = 0; i < reg_num; i++) {
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info,
+ COMMON_INIT_TBL_VT1636[i]);
+ }
+
+ /* Input Data Mode Select */
+ if (plvds_setting_info->device_lcd_dualedge) {
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info,
+ DUAL_CHANNEL_ENABLE_TBL_VT1636[0]);
+ } else {
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info,
+ SINGLE_CHANNEL_ENABLE_TBL_VT1636[0]);
+ }
+
+ if (plvds_setting_info->LCDDithering) {
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info,
+ DITHERING_ENABLE_TBL_VT1636[0]);
+ } else {
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info,
+ DITHERING_DISABLE_TBL_VT1636[0]);
+ }
+}
+
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+ VDD_ON_TBL_VT1636[0]);
+
+ /* Pad on: */
+ switch (plvds_chip_info->output_interface) {
+ case INTERFACE_DVP0:
+ {
+ viafb_write_reg_mask(SR1E, VIASR, 0xC0, 0xC0);
+ break;
+ }
+
+ case INTERFACE_DVP1:
+ {
+ viafb_write_reg_mask(SR1E, VIASR, 0x30, 0x30);
+ break;
+ }
+
+ case INTERFACE_DFP_LOW:
+ {
+ viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x03);
+ break;
+ }
+
+ case INTERFACE_DFP_HIGH:
+ {
+ viafb_write_reg_mask(SR2A, VIASR, 0x03, 0x0C);
+ break;
+ }
+
+ }
+}
+
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+ VDD_OFF_TBL_VT1636[0]);
+
+ /* Pad off: */
+ switch (plvds_chip_info->output_interface) {
+ case INTERFACE_DVP0:
+ {
+ viafb_write_reg_mask(SR1E, VIASR, 0x00, 0xC0);
+ break;
+ }
+
+ case INTERFACE_DVP1:
+ {
+ viafb_write_reg_mask(SR1E, VIASR, 0x00, 0x30);
+ break;
+ }
+
+ case INTERFACE_DFP_LOW:
+ {
+ viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x03);
+ break;
+ }
+
+ case INTERFACE_DFP_HIGH:
+ {
+ viafb_write_reg_mask(SR2A, VIASR, 0x00, 0x0C);
+ break;
+ }
+
+ }
+}
+
+bool viafb_lvds_identify_vt1636(void)
+{
+ u8 Buffer[2];
+
+ DEBUG_MSG(KERN_INFO "viafb_lvds_identify_vt1636.\n");
+
+ /* Sense VT1636 LVDS Transmiter */
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_slave_addr =
+ VT1636_LVDS_I2C_ADDR;
+
+ /* Check vendor ID first: */
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_slave_addr,
+ 0x00, &Buffer[0]);
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_slave_addr,
+ 0x01, &Buffer[1]);
+
+ if (!((Buffer[0] == 0x06) && (Buffer[1] == 0x11)))
+ return false;
+
+ /* Check Chip ID: */
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_slave_addr,
+ 0x02, &Buffer[0]);
+ viafb_i2c_readbyte((u8) viaparinfo->chip_info->lvds_chip_info.
+ lvds_chip_slave_addr,
+ 0x03, &Buffer[1]);
+ if ((Buffer[0] == 0x45) && (Buffer[1] == 0x33)) {
+ viaparinfo->chip_info->lvds_chip_info.lvds_chip_name =
+ VT1636_LVDS;
+ return true;
+ }
+
+ return false;
+}
+
+static int get_clk_range_index(u32 Clk)
+{
+ if (Clk < DPA_CLK_30M)
+ return DPA_CLK_RANGE_30M;
+ else if (Clk < DPA_CLK_50M)
+ return DPA_CLK_RANGE_30_50M;
+ else if (Clk < DPA_CLK_70M)
+ return DPA_CLK_RANGE_50_70M;
+ else if (Clk < DPA_CLK_100M)
+ return DPA_CLK_RANGE_70_100M;
+ else if (Clk < DPA_CLK_150M)
+ return DPA_CLK_RANGE_100_150M;
+ else
+ return DPA_CLK_RANGE_150M;
+}
+
+static int get_lvds_dpa_setting_index(int panel_size_id,
+ struct VT1636_DPA_SETTING *p_vt1636_dpasetting_tbl,
+ int tbl_size)
+{
+ int i;
+
+ for (i = 0; i < tbl_size; i++) {
+ if (panel_size_id == p_vt1636_dpasetting_tbl->PanelSizeID)
+ return i;
+
+ p_vt1636_dpasetting_tbl++;
+ }
+
+ return 0;
+}
+
+static void set_dpa_vt1636(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info,
+ struct VT1636_DPA_SETTING *p_vt1636_dpa_setting)
+{
+ struct IODATA io_data;
+
+ io_data.Index = 0x09;
+ io_data.Mask = 0x1F;
+ io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST1;
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info,
+ plvds_chip_info, io_data);
+
+ io_data.Index = 0x08;
+ io_data.Mask = 0x0F;
+ io_data.Data = p_vt1636_dpa_setting->CLK_SEL_ST2;
+ viafb_gpio_i2c_write_mask_lvds(plvds_setting_info, plvds_chip_info,
+ io_data);
+}
+
+void viafb_vt1636_patch_skew_on_vt3324(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ int index, size;
+
+ DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3324.\n");
+
+ /* Graphics DPA settings: */
+ index = get_clk_range_index(plvds_setting_info->vclk);
+ viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+ &GFX_DPA_SETTING_TBL_VT3324[index]);
+
+ /* LVDS Transmitter DPA settings: */
+ size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3324);
+ index =
+ get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id,
+ VT1636_DPA_SETTING_TBL_VT3324, size);
+ set_dpa_vt1636(plvds_setting_info, plvds_chip_info,
+ &VT1636_DPA_SETTING_TBL_VT3324[index]);
+}
+
+void viafb_vt1636_patch_skew_on_vt3327(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ int index, size;
+
+ DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3327.\n");
+
+ /* Graphics DPA settings: */
+ index = get_clk_range_index(plvds_setting_info->vclk);
+ viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+ &GFX_DPA_SETTING_TBL_VT3327[index]);
+
+ /* LVDS Transmitter DPA settings: */
+ size = ARRAY_SIZE(VT1636_DPA_SETTING_TBL_VT3327);
+ index =
+ get_lvds_dpa_setting_index(plvds_setting_info->lcd_panel_id,
+ VT1636_DPA_SETTING_TBL_VT3327, size);
+ set_dpa_vt1636(plvds_setting_info, plvds_chip_info,
+ &VT1636_DPA_SETTING_TBL_VT3327[index]);
+}
+
+void viafb_vt1636_patch_skew_on_vt3364(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info)
+{
+ int index;
+
+ DEBUG_MSG(KERN_INFO "viafb_vt1636_patch_skew_on_vt3364.\n");
+
+ /* Graphics DPA settings: */
+ index = get_clk_range_index(plvds_setting_info->vclk);
+ viafb_set_dpa_gfx(plvds_chip_info->output_interface,
+ &GFX_DPA_SETTING_TBL_VT3364[index]);
+}
diff --git a/drivers/video/via/vt1636.h b/drivers/video/via/vt1636.h
new file mode 100644
index 00000000000..2a150c58c7e
--- /dev/null
+++ b/drivers/video/via/vt1636.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 1998-2008 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved.
+
+ * 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 WARRANTIES OR REPRESENTATIONS; 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 _VT1636_H_
+#define _VT1636_H_
+#include "chip.h"
+bool viafb_lvds_identify_vt1636(void);
+void viafb_init_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info, struct lvds_chip_information *plvds_chip_info);
+void viafb_enable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_disable_lvds_vt1636(struct lvds_setting_information
+ *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3324(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3327(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+void viafb_vt1636_patch_skew_on_vt3364(
+ struct lvds_setting_information *plvds_setting_info,
+ struct lvds_chip_information *plvds_chip_info);
+
+#endif
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c
index 10211e49300..29e144f81cb 100644
--- a/drivers/w1/masters/ds1wm.c
+++ b/drivers/w1/masters/ds1wm.c
@@ -160,8 +160,10 @@ static int ds1wm_reset(struct ds1wm_data *ds1wm_data)
* 625 us - 60 us - 240 us - 100 ns = 324.9 us
*
* We'll wait a bit longer just to be sure.
+ * Was udelay(500), but if it is going to busywait the cpu that long,
+ * might as well come back later.
*/
- udelay(500);
+ msleep(1);
ds1wm_write_register(ds1wm_data, DS1WM_INT_EN,
DS1WM_INTEN_ERBF | DS1WM_INTEN_ETMT | DS1WM_INTEN_EPD |
@@ -274,8 +276,8 @@ static u8 ds1wm_reset_bus(void *data)
return 0;
}
-static void ds1wm_search(void *data, u8 search_type,
- w1_slave_found_callback slave_found)
+static void ds1wm_search(void *data, struct w1_master *master_dev,
+ u8 search_type, w1_slave_found_callback slave_found)
{
struct ds1wm_data *ds1wm_data = data;
int i;
@@ -313,7 +315,7 @@ static void ds1wm_search(void *data, u8 search_type,
ds1wm_write_register(ds1wm_data, DS1WM_CMD, ~DS1WM_CMD_SRA);
ds1wm_reset(ds1wm_data);
- slave_found(ds1wm_data, rom_id);
+ slave_found(master_dev, rom_id);
}
/* --------------------------------------------------------------------- */
diff --git a/drivers/w1/masters/ds2490.c b/drivers/w1/masters/ds2490.c
index b63b5e044a4..59ad6e95af8 100644
--- a/drivers/w1/masters/ds2490.c
+++ b/drivers/w1/masters/ds2490.c
@@ -88,7 +88,7 @@
#define COMM_DT 0x2000
#define COMM_SPU 0x1000
#define COMM_F 0x0800
-#define COMM_NTP 0x0400
+#define COMM_NTF 0x0400
#define COMM_ICP 0x0200
#define COMM_RST 0x0100
@@ -98,11 +98,6 @@
#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 */
@@ -112,6 +107,17 @@
#define ST_IDLE 0x20 /* DS2490 is currently idle */
#define ST_EPOF 0x80
+/* Result Register flags */
+#define RR_DETECT 0xA5 /* New device detected */
+#define RR_NRS 0x01 /* Reset no presence or ... */
+#define RR_SH 0x02 /* short on reset or set path */
+#define RR_APP 0x04 /* alarming presence on reset */
+#define RR_VPP 0x08 /* 12V expected not seen */
+#define RR_CMP 0x10 /* compare error */
+#define RR_CRC 0x20 /* CRC error detected */
+#define RR_RDP 0x40 /* redirected page */
+#define RR_EOS 0x80 /* end of search error */
+
#define SPEED_NORMAL 0x00
#define SPEED_FLEXIBLE 0x01
#define SPEED_OVERDRIVE 0x02
@@ -131,6 +137,15 @@ struct ds_device
int ep[NUM_EP];
+ /* Strong PullUp
+ * 0: pullup not active, else duration in milliseconds
+ */
+ int spu_sleep;
+ /* spu_bit contains COMM_SPU or 0 depending on if the strong pullup
+ * should be active or not for writes.
+ */
+ u16 spu_bit;
+
struct w1_bus_master master;
};
@@ -164,7 +179,6 @@ 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 *);
-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_cmd(struct ds_device *, u16, u16);
@@ -192,7 +206,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;
@@ -207,7 +221,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;
@@ -223,11 +237,6 @@ static int ds_send_control(struct ds_device *dev, u16 value, u16 index)
return err;
}
-static inline void ds_dump_status(unsigned char *buf, unsigned char *str, int off)
-{
- printk("%45s: %8x\n", str, buf[off]);
-}
-
static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
unsigned char *buf, int size)
{
@@ -248,62 +257,81 @@ static int ds_recv_status_nodump(struct ds_device *dev, struct ds_status *st,
return count;
}
-static int ds_recv_status(struct ds_device *dev, struct ds_status *st)
+static inline void ds_print_msg(unsigned char *buf, unsigned char *str, int off)
{
- unsigned char buf[64];
- int count, err = 0, i;
-
- memcpy(st, buf, sizeof(*st));
+ printk(KERN_INFO "%45s: %8x\n", str, buf[off]);
+}
- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
- if (count < 0)
- return err;
+static void ds_dump_status(struct ds_device *dev, unsigned char *buf, int count)
+{
+ int i;
- printk("0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
+ printk(KERN_INFO "0x%x: count=%d, status: ", dev->ep[EP_STATUS], count);
for (i=0; i<count; ++i)
printk("%02x ", buf[i]);
- printk("\n");
+ printk(KERN_INFO "\n");
if (count >= 16) {
- ds_dump_status(buf, "enable flag", 0);
- ds_dump_status(buf, "1-wire speed", 1);
- ds_dump_status(buf, "strong pullup duration", 2);
- ds_dump_status(buf, "programming pulse duration", 3);
- ds_dump_status(buf, "pulldown slew rate control", 4);
- ds_dump_status(buf, "write-1 low time", 5);
- ds_dump_status(buf, "data sample offset/write-0 recovery time", 6);
- ds_dump_status(buf, "reserved (test register)", 7);
- ds_dump_status(buf, "device status flags", 8);
- ds_dump_status(buf, "communication command byte 1", 9);
- ds_dump_status(buf, "communication command byte 2", 10);
- ds_dump_status(buf, "communication command buffer status", 11);
- ds_dump_status(buf, "1-wire data output buffer status", 12);
- ds_dump_status(buf, "1-wire data input buffer status", 13);
- ds_dump_status(buf, "reserved", 14);
- ds_dump_status(buf, "reserved", 15);
+ ds_print_msg(buf, "enable flag", 0);
+ ds_print_msg(buf, "1-wire speed", 1);
+ ds_print_msg(buf, "strong pullup duration", 2);
+ ds_print_msg(buf, "programming pulse duration", 3);
+ ds_print_msg(buf, "pulldown slew rate control", 4);
+ ds_print_msg(buf, "write-1 low time", 5);
+ ds_print_msg(buf, "data sample offset/write-0 recovery time",
+ 6);
+ ds_print_msg(buf, "reserved (test register)", 7);
+ ds_print_msg(buf, "device status flags", 8);
+ ds_print_msg(buf, "communication command byte 1", 9);
+ ds_print_msg(buf, "communication command byte 2", 10);
+ ds_print_msg(buf, "communication command buffer status", 11);
+ ds_print_msg(buf, "1-wire data output buffer status", 12);
+ ds_print_msg(buf, "1-wire data input buffer status", 13);
+ ds_print_msg(buf, "reserved", 14);
+ ds_print_msg(buf, "reserved", 15);
}
-
- memcpy(st, buf, sizeof(*st));
-
- if (st->status & ST_EPOF) {
- printk(KERN_INFO "Resetting device after ST_EPOF.\n");
- err = ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
- if (err)
- return err;
- count = ds_recv_status_nodump(dev, st, buf, sizeof(buf));
- if (count < 0)
- return err;
- }
-#if 0
- if (st->status & ST_IDLE) {
- printk(KERN_INFO "Resetting pulse after ST_IDLE.\n");
- err = ds_start_pulse(dev, PULLUP_PULSE_DURATION);
- if (err)
- return err;
+ for (i = 16; i < count; ++i) {
+ if (buf[i] == RR_DETECT) {
+ ds_print_msg(buf, "new device detect", i);
+ continue;
+ }
+ ds_print_msg(buf, "Result Register Value: ", i);
+ if (buf[i] & RR_NRS)
+ printk(KERN_INFO "NRS: Reset no presence or ...\n");
+ if (buf[i] & RR_SH)
+ printk(KERN_INFO "SH: short on reset or set path\n");
+ if (buf[i] & RR_APP)
+ printk(KERN_INFO "APP: alarming presence on reset\n");
+ if (buf[i] & RR_VPP)
+ printk(KERN_INFO "VPP: 12V expected not seen\n");
+ if (buf[i] & RR_CMP)
+ printk(KERN_INFO "CMP: compare error\n");
+ if (buf[i] & RR_CRC)
+ printk(KERN_INFO "CRC: CRC error detected\n");
+ if (buf[i] & RR_RDP)
+ printk(KERN_INFO "RDP: redirected page\n");
+ if (buf[i] & RR_EOS)
+ printk(KERN_INFO "EOS: end of search error\n");
}
-#endif
+}
- return err;
+static void ds_reset_device(struct ds_device *dev)
+{
+ ds_send_control_cmd(dev, CTL_RESET_DEVICE, 0);
+ /* Always allow strong pullup which allow individual writes to use
+ * the strong pullup.
+ */
+ if (ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE))
+ printk(KERN_ERR "ds_reset_device: "
+ "Error allowing strong pullup\n");
+ /* Chip strong pullup time was cleared. */
+ if (dev->spu_sleep) {
+ /* lower 4 bits are 0, see ds_set_pullup */
+ u8 del = dev->spu_sleep>>4;
+ if (ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del))
+ printk(KERN_ERR "ds_reset_device: "
+ "Error setting duration\n");
+ }
}
static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
@@ -311,13 +339,27 @@ static int ds_recv_data(struct ds_device *dev, unsigned char *buf, int size)
int count, err;
struct ds_status st;
+ /* Careful on size. If size is less than what is available in
+ * the input buffer, the device fails the bulk transfer and
+ * clears the input buffer. It could read the maximum size of
+ * the data buffer, but then do you return the first, last, or
+ * some set of the middle size bytes? As long as the rest of
+ * the code is correct there will be size bytes waiting. A
+ * call to ds_wait_status will wait until the device is idle
+ * and any data to be received would have been available.
+ */
count = 0;
err = usb_bulk_msg(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]),
buf, size, &count, 1000);
if (err < 0) {
+ u8 buf[0x20];
+ int count;
+
printk(KERN_INFO "Clearing ep0x%x.\n", dev->ep[EP_DATA_IN]);
usb_clear_halt(dev->udev, usb_rcvbulkpipe(dev->udev, dev->ep[EP_DATA_IN]));
- ds_recv_status(dev, &st);
+
+ count = ds_recv_status_nodump(dev, &st, buf, sizeof(buf));
+ ds_dump_status(dev, buf, count);
return err;
}
@@ -341,7 +383,8 @@ static int ds_send_data(struct ds_device *dev, unsigned char *buf, int len)
count = 0;
err = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, dev->ep[EP_DATA_OUT]), buf, len, &count, 1000);
if (err < 0) {
- printk(KERN_ERR "Failed to read 1-wire data from 0x02: err=%d.\n", err);
+ printk(KERN_ERR "Failed to write 1-wire data to ep0x%x: "
+ "err=%d.\n", dev->ep[EP_DATA_OUT], err);
return err;
}
@@ -397,7 +440,7 @@ int ds_detect(struct ds_device *dev, struct ds_status *st)
if (err)
return err;
- err = ds_recv_status(dev, st);
+ err = ds_dump_status(dev, st);
return err;
}
@@ -420,33 +463,49 @@ static int ds_wait_status(struct ds_device *dev, struct ds_status *st)
printk("\n");
}
#endif
- } while(!(buf[0x08] & 0x20) && !(err < 0) && ++count < 100);
+ } while (!(buf[0x08] & ST_IDLE) && !(err < 0) && ++count < 100);
+
+ if (err >= 16 && st->status & ST_EPOF) {
+ printk(KERN_INFO "Resetting device after ST_EPOF.\n");
+ ds_reset_device(dev);
+ /* Always dump the device status. */
+ count = 101;
+ }
+ /* Dump the status for errors or if there is extended return data.
+ * The extended status includes new device detection (maybe someone
+ * can do something with it).
+ */
+ if (err > 16 || count >= 100 || err < 0)
+ ds_dump_status(dev, buf, err);
- if (((err > 16) && (buf[0x10] & 0x01)) || count >= 100 || err < 0) {
- ds_recv_status(dev, st);
+ /* Extended data isn't an error. Well, a short is, but the dump
+ * would have already told the user that and we can't do anything
+ * about it in software anyway.
+ */
+ if (count >= 100 || err < 0)
return -1;
- } else
+ else
return 0;
}
-static int ds_reset(struct ds_device *dev, struct ds_status *st)
+static int ds_reset(struct ds_device *dev)
{
int err;
- //err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_F | COMM_IM | COMM_SE, SPEED_FLEXIBLE);
- err = ds_send_control(dev, 0x43, SPEED_NORMAL);
+ /* Other potentionally interesting flags for reset.
+ *
+ * COMM_NTF: Return result register feedback. This could be used to
+ * detect some conditions such as short, alarming presence, or
+ * detect if a new device was detected.
+ *
+ * COMM_SE which allows SPEED_NORMAL, SPEED_FLEXIBLE, SPEED_OVERDRIVE:
+ * Select the data transfer rate.
+ */
+ err = ds_send_control(dev, COMM_1_WIRE_RESET | COMM_IM, SPEED_NORMAL);
if (err)
return err;
- ds_wait_status(dev, st);
-#if 0
- if (st->command_buffer_status) {
- printk(KERN_INFO "Short circuit.\n");
- return -EIO;
- }
-#endif
-
return 0;
}
@@ -471,60 +530,43 @@ static int ds_set_speed(struct ds_device *dev, int speed)
}
#endif /* 0 */
-static int ds_start_pulse(struct ds_device *dev, int delay)
+static int ds_set_pullup(struct ds_device *dev, int delay)
{
- int err;
+ int err = 0;
u8 del = 1 + (u8)(delay >> 4);
- struct ds_status st;
-
-#if 0
- err = ds_stop_pulse(dev, 10);
- if (err)
+ /* Just storing delay would not get the trunication and roundup. */
+ int ms = del<<4;
+
+ /* Enable spu_bit if a delay is set. */
+ dev->spu_bit = delay ? COMM_SPU : 0;
+ /* If delay is zero, it has already been disabled, if the time is
+ * the same as the hardware was last programmed to, there is also
+ * nothing more to do. Compare with the recalculated value ms
+ * rather than del or delay which can have a different value.
+ */
+ if (delay == 0 || ms == dev->spu_sleep)
return err;
- err = ds_send_control_mode(dev, MOD_PULSE_EN, PULSE_SPUE);
- if (err)
- return err;
-#endif
err = ds_send_control(dev, COMM_SET_DURATION | COMM_IM, del);
if (err)
return err;
- err = ds_send_control(dev, COMM_PULSE | COMM_IM | COMM_F, 0);
- if (err)
- return err;
-
- mdelay(delay);
-
- ds_wait_status(dev, &st);
+ dev->spu_sleep = ms;
return err;
}
static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
{
- int err, count;
+ int err;
struct ds_status st;
- u16 value = (COMM_BIT_IO | COMM_IM) | ((bit) ? COMM_D : 0);
- u16 cmd;
- err = ds_send_control(dev, value, 0);
+ err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit ? COMM_D : 0),
+ 0);
if (err)
return err;
- count = 0;
- do {
- err = ds_wait_status(dev, &st);
- if (err)
- return err;
-
- cmd = st.command0 | (st.command1 << 8);
- } while (cmd != value && ++count < 10);
-
- if (err < 0 || count >= 10) {
- printk(KERN_ERR "Failed to obtain status.\n");
- return -EINVAL;
- }
+ ds_wait_status(dev, &st);
err = ds_recv_data(dev, tbit, sizeof(*tbit));
if (err < 0)
@@ -533,12 +575,18 @@ static int ds_touch_bit(struct ds_device *dev, u8 bit, u8 *tbit)
return 0;
}
+#if 0
static int ds_write_bit(struct ds_device *dev, u8 bit)
{
int err;
struct ds_status st;
- err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | (bit) ? COMM_D : 0, 0);
+ /* Set COMM_ICP to write without a readback. Note, this will
+ * produce one time slot, a down followed by an up with COMM_D
+ * only determing the timing.
+ */
+ err = ds_send_control(dev, COMM_BIT_IO | COMM_IM | COMM_ICP |
+ (bit ? COMM_D : 0), 0);
if (err)
return err;
@@ -546,6 +594,7 @@ static int ds_write_bit(struct ds_device *dev, u8 bit)
return 0;
}
+#endif
static int ds_write_byte(struct ds_device *dev, u8 byte)
{
@@ -553,10 +602,13 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
struct ds_status st;
u8 rbyte;
- err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | COMM_SPU, byte);
+ err = ds_send_control(dev, COMM_BYTE_IO | COMM_IM | dev->spu_bit, byte);
if (err)
return err;
+ if (dev->spu_bit)
+ msleep(dev->spu_sleep);
+
err = ds_wait_status(dev, &st);
if (err)
return err;
@@ -565,8 +617,6 @@ static int ds_write_byte(struct ds_device *dev, u8 byte)
if (err < 0)
return err;
- ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
return !(byte == rbyte);
}
@@ -602,7 +652,7 @@ static int ds_read_block(struct ds_device *dev, u8 *buf, int len)
if (err < 0)
return err;
- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM, len);
if (err)
return err;
@@ -623,20 +673,19 @@ static int ds_write_block(struct ds_device *dev, u8 *buf, int len)
if (err < 0)
return err;
- ds_wait_status(dev, &st);
-
- err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | COMM_SPU, len);
+ err = ds_send_control(dev, COMM_BLOCK_IO | COMM_IM | dev->spu_bit, len);
if (err)
return err;
+ if (dev->spu_bit)
+ msleep(dev->spu_sleep);
+
ds_wait_status(dev, &st);
err = ds_recv_data(dev, buf, len);
if (err < 0)
return err;
- ds_start_pulse(dev, PULLUP_PULSE_DURATION);
-
return !(err == len);
}
@@ -728,6 +777,7 @@ static u8 ds9490r_touch_bit(void *data, u8 bit)
return ret;
}
+#if 0
static void ds9490r_write_bit(void *data, u8 bit)
{
struct ds_device *dev = data;
@@ -735,13 +785,6 @@ static void ds9490r_write_bit(void *data, u8 bit)
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;
@@ -754,6 +797,14 @@ static u8 ds9490r_read_bit(void *data)
return bit & 1;
}
+#endif
+
+static void ds9490r_write_byte(void *data, u8 byte)
+{
+ struct ds_device *dev = data;
+
+ ds_write_byte(dev, byte);
+}
static u8 ds9490r_read_byte(void *data)
{
@@ -790,31 +841,58 @@ static u8 ds9490r_read_block(void *data, u8 *buf, int 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);
+ err = ds_reset(dev);
if (err)
return 1;
return 0;
}
+static u8 ds9490r_set_pullup(void *data, int delay)
+{
+ struct ds_device *dev = data;
+
+ if (ds_set_pullup(dev, delay))
+ return 1;
+
+ return 0;
+}
+
static int ds_w1_init(struct ds_device *dev)
{
memset(&dev->master, 0, sizeof(struct w1_bus_master));
+ /* Reset the device as it can be in a bad state.
+ * This is necessary because a block write will wait for data
+ * to be placed in the output buffer and block any later
+ * commands which will keep accumulating and the device will
+ * not be idle. Another case is removing the ds2490 module
+ * while a bus search is in progress, somehow a few commands
+ * get through, but the input transfers fail leaving data in
+ * the input buffer. This will cause the next read to fail
+ * see the note in ds_recv_data.
+ */
+ ds_reset_device(dev);
+
dev->master.data = dev;
dev->master.touch_bit = &ds9490r_touch_bit;
+ /* read_bit and write_bit in w1_bus_master are expected to set and
+ * sample the line level. For write_bit that means it is expected to
+ * set it to that value and leave it there. ds2490 only supports an
+ * individual time slot at the lowest level. The requirement from
+ * pulling the bus state down to reading the state is 15us, something
+ * that isn't realistic on the USB bus anyway.
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;
+ dev->master.set_pullup = &ds9490r_set_pullup;
return w1_add_master_device(&dev->master);
}
@@ -838,6 +916,8 @@ static int ds_probe(struct usb_interface *intf,
printk(KERN_INFO "Failed to allocate new DS9490R structure.\n");
return -ENOMEM;
}
+ dev->spu_sleep = 0;
+ dev->spu_bit = 0;
dev->udev = usb_get_dev(udev);
if (!dev->udev) {
err = -ENOMEM;
diff --git a/drivers/w1/slaves/w1_ds2431.c b/drivers/w1/slaves/w1_ds2431.c
new file mode 100644
index 00000000000..2c6c0cf6a20
--- /dev/null
+++ b/drivers/w1/slaves/w1_ds2431.c
@@ -0,0 +1,312 @@
+/*
+ * w1_ds2431.c - w1 family 2d (DS2431) driver
+ *
+ * Copyright (c) 2008 Bernhard Weirich <bernhard.weirich@riedel.net>
+ *
+ * Heavily inspired by w1_DS2433 driver from Ben Gardner <bgardner@wabtec.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+
+#include "../w1.h"
+#include "../w1_int.h"
+#include "../w1_family.h"
+
+#define W1_F2D_EEPROM_SIZE 128
+#define W1_F2D_PAGE_COUNT 4
+#define W1_F2D_PAGE_BITS 5
+#define W1_F2D_PAGE_SIZE (1<<W1_F2D_PAGE_BITS)
+#define W1_F2D_PAGE_MASK 0x1F
+
+#define W1_F2D_SCRATCH_BITS 3
+#define W1_F2D_SCRATCH_SIZE (1<<W1_F2D_SCRATCH_BITS)
+#define W1_F2D_SCRATCH_MASK (W1_F2D_SCRATCH_SIZE-1)
+
+#define W1_F2D_READ_EEPROM 0xF0
+#define W1_F2D_WRITE_SCRATCH 0x0F
+#define W1_F2D_READ_SCRATCH 0xAA
+#define W1_F2D_COPY_SCRATCH 0x55
+
+
+#define W1_F2D_TPROG_MS 11
+
+#define W1_F2D_READ_RETRIES 10
+#define W1_F2D_READ_MAXLEN 8
+
+/*
+ * Check the file size bounds and adjusts count as needed.
+ * This would not be needed if the file size didn't reset to 0 after a write.
+ */
+static inline size_t w1_f2d_fix_count(loff_t off, size_t count, size_t size)
+{
+ if (off > size)
+ return 0;
+
+ if ((off + count) > size)
+ return size - off;
+
+ return count;
+}
+
+/*
+ * Read a block from W1 ROM two times and compares the results.
+ * If they are equal they are returned, otherwise the read
+ * is repeated W1_F2D_READ_RETRIES times.
+ *
+ * count must not exceed W1_F2D_READ_MAXLEN.
+ */
+static int w1_f2d_readblock(struct w1_slave *sl, int off, int count, char *buf)
+{
+ u8 wrbuf[3];
+ u8 cmp[W1_F2D_READ_MAXLEN];
+ int tries = W1_F2D_READ_RETRIES;
+
+ do {
+ wrbuf[0] = W1_F2D_READ_EEPROM;
+ wrbuf[1] = off & 0xff;
+ wrbuf[2] = off >> 8;
+
+ if (w1_reset_select_slave(sl))
+ return -1;
+
+ w1_write_block(sl->master, wrbuf, 3);
+ w1_read_block(sl->master, buf, count);
+
+ if (w1_reset_select_slave(sl))
+ return -1;
+
+ w1_write_block(sl->master, wrbuf, 3);
+ w1_read_block(sl->master, cmp, count);
+
+ if (!memcmp(cmp, buf, count))
+ return 0;
+ } while (--tries);
+
+ dev_err(&sl->dev, "proof reading failed %d times\n",
+ W1_F2D_READ_RETRIES);
+
+ return -1;
+}
+
+static ssize_t w1_f2d_read_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ int todo = count;
+
+ count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+ if (count == 0)
+ return 0;
+
+ mutex_lock(&sl->master->mutex);
+
+ /* read directly from the EEPROM in chunks of W1_F2D_READ_MAXLEN */
+ while (todo > 0) {
+ int block_read;
+
+ if (todo >= W1_F2D_READ_MAXLEN)
+ block_read = W1_F2D_READ_MAXLEN;
+ else
+ block_read = todo;
+
+ if (w1_f2d_readblock(sl, off, block_read, buf) < 0)
+ count = -EIO;
+
+ todo -= W1_F2D_READ_MAXLEN;
+ buf += W1_F2D_READ_MAXLEN;
+ off += W1_F2D_READ_MAXLEN;
+ }
+
+ mutex_unlock(&sl->master->mutex);
+
+ return count;
+}
+
+/*
+ * Writes to the scratchpad and reads it back for verification.
+ * Then copies the scratchpad to EEPROM.
+ * The data must be aligned at W1_F2D_SCRATCH_SIZE bytes and
+ * must be W1_F2D_SCRATCH_SIZE bytes long.
+ * The master must be locked.
+ *
+ * @param sl The slave structure
+ * @param addr Address for the write
+ * @param len length must be <= (W1_F2D_PAGE_SIZE - (addr & W1_F2D_PAGE_MASK))
+ * @param data The data to write
+ * @return 0=Success -1=failure
+ */
+static int w1_f2d_write(struct w1_slave *sl, int addr, int len, const u8 *data)
+{
+ int tries = W1_F2D_READ_RETRIES;
+ u8 wrbuf[4];
+ u8 rdbuf[W1_F2D_SCRATCH_SIZE + 3];
+ u8 es = (addr + len - 1) % W1_F2D_SCRATCH_SIZE;
+
+retry:
+
+ /* Write the data to the scratchpad */
+ if (w1_reset_select_slave(sl))
+ return -1;
+
+ wrbuf[0] = W1_F2D_WRITE_SCRATCH;
+ wrbuf[1] = addr & 0xff;
+ wrbuf[2] = addr >> 8;
+
+ w1_write_block(sl->master, wrbuf, 3);
+ w1_write_block(sl->master, data, len);
+
+ /* Read the scratchpad and verify */
+ if (w1_reset_select_slave(sl))
+ return -1;
+
+ w1_write_8(sl->master, W1_F2D_READ_SCRATCH);
+ w1_read_block(sl->master, rdbuf, len + 3);
+
+ /* Compare what was read against the data written */
+ if ((rdbuf[0] != wrbuf[1]) || (rdbuf[1] != wrbuf[2]) ||
+ (rdbuf[2] != es) || (memcmp(data, &rdbuf[3], len) != 0)) {
+
+ if (--tries)
+ goto retry;
+
+ dev_err(&sl->dev,
+ "could not write to eeprom, scratchpad compare failed %d times\n",
+ W1_F2D_READ_RETRIES);
+
+ return -1;
+ }
+
+ /* Copy the scratchpad to EEPROM */
+ if (w1_reset_select_slave(sl))
+ return -1;
+
+ wrbuf[0] = W1_F2D_COPY_SCRATCH;
+ wrbuf[3] = es;
+ w1_write_block(sl->master, wrbuf, 4);
+
+ /* Sleep for tprog ms to wait for the write to complete */
+ msleep(W1_F2D_TPROG_MS);
+
+ /* Reset the bus to wake up the EEPROM */
+ w1_reset_bus(sl->master);
+
+ return 0;
+}
+
+static ssize_t w1_f2d_write_bin(struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ int addr, len;
+ int copy;
+
+ count = w1_f2d_fix_count(off, count, W1_F2D_EEPROM_SIZE);
+ if (count == 0)
+ return 0;
+
+ mutex_lock(&sl->master->mutex);
+
+ /* Can only write data in blocks of the size of the scratchpad */
+ addr = off;
+ len = count;
+ while (len > 0) {
+
+ /* if len too short or addr not aligned */
+ if (len < W1_F2D_SCRATCH_SIZE || addr & W1_F2D_SCRATCH_MASK) {
+ char tmp[W1_F2D_SCRATCH_SIZE];
+
+ /* read the block and update the parts to be written */
+ if (w1_f2d_readblock(sl, addr & ~W1_F2D_SCRATCH_MASK,
+ W1_F2D_SCRATCH_SIZE, tmp)) {
+ count = -EIO;
+ goto out_up;
+ }
+
+ /* copy at most to the boundary of the PAGE or len */
+ copy = W1_F2D_SCRATCH_SIZE -
+ (addr & W1_F2D_SCRATCH_MASK);
+
+ if (copy > len)
+ copy = len;
+
+ memcpy(&tmp[addr & W1_F2D_SCRATCH_MASK], buf, copy);
+ if (w1_f2d_write(sl, addr & ~W1_F2D_SCRATCH_MASK,
+ W1_F2D_SCRATCH_SIZE, tmp) < 0) {
+ count = -EIO;
+ goto out_up;
+ }
+ } else {
+
+ copy = W1_F2D_SCRATCH_SIZE;
+ if (w1_f2d_write(sl, addr, copy, buf) < 0) {
+ count = -EIO;
+ goto out_up;
+ }
+ }
+ buf += copy;
+ addr += copy;
+ len -= copy;
+ }
+
+out_up:
+ mutex_unlock(&sl->master->mutex);
+
+ return count;
+}
+
+static struct bin_attribute w1_f2d_bin_attr = {
+ .attr = {
+ .name = "eeprom",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .size = W1_F2D_EEPROM_SIZE,
+ .read = w1_f2d_read_bin,
+ .write = w1_f2d_write_bin,
+};
+
+static int w1_f2d_add_slave(struct w1_slave *sl)
+{
+ return sysfs_create_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
+}
+
+static void w1_f2d_remove_slave(struct w1_slave *sl)
+{
+ sysfs_remove_bin_file(&sl->dev.kobj, &w1_f2d_bin_attr);
+}
+
+static struct w1_family_ops w1_f2d_fops = {
+ .add_slave = w1_f2d_add_slave,
+ .remove_slave = w1_f2d_remove_slave,
+};
+
+static struct w1_family w1_family_2d = {
+ .fid = W1_EEPROM_DS2431,
+ .fops = &w1_f2d_fops,
+};
+
+static int __init w1_f2d_init(void)
+{
+ return w1_register_family(&w1_family_2d);
+}
+
+static void __exit w1_f2d_fini(void)
+{
+ w1_unregister_family(&w1_family_2d);
+}
+
+module_init(w1_f2d_init);
+module_exit(w1_f2d_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Bernhard Weirich <bernhard.weirich@riedel.net>");
+MODULE_DESCRIPTION("w1 family 2d driver for DS2431, 1kb EEPROM");
diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c
index fb28acaeed6..2c8dff9f77d 100644
--- a/drivers/w1/slaves/w1_therm.c
+++ b/drivers/w1/slaves/w1_therm.c
@@ -37,31 +37,33 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol, temperature family.");
+/* Allow the strong pullup to be disabled, but default to enabled.
+ * If it was disabled a parasite powered device might not get the require
+ * current to do a temperature conversion. If it is enabled parasite powered
+ * devices have a better chance of getting the current required.
+ */
+static int w1_strong_pullup = 1;
+module_param_named(strong_pullup, w1_strong_pullup, int, 0);
+
static u8 bad_roms[][9] = {
{0xaa, 0x00, 0x4b, 0x46, 0xff, 0xff, 0x0c, 0x10, 0x87},
{}
};
-static ssize_t w1_therm_read_bin(struct kobject *, struct bin_attribute *,
- char *, loff_t, size_t);
+static ssize_t w1_therm_read(struct device *device,
+ struct device_attribute *attr, char *buf);
-static struct bin_attribute w1_therm_bin_attr = {
- .attr = {
- .name = "w1_slave",
- .mode = S_IRUGO,
- },
- .size = W1_SLAVE_DATA_SIZE,
- .read = w1_therm_read_bin,
-};
+static struct device_attribute w1_therm_attr =
+ __ATTR(w1_slave, S_IRUGO, w1_therm_read, NULL);
static int w1_therm_add_slave(struct w1_slave *sl)
{
- return sysfs_create_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+ return device_create_file(&sl->dev, &w1_therm_attr);
}
static void w1_therm_remove_slave(struct w1_slave *sl)
{
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_therm_bin_attr);
+ device_remove_file(&sl->dev, &w1_therm_attr);
}
static struct w1_family_ops w1_therm_fops = {
@@ -160,30 +162,19 @@ static int w1_therm_check_rom(u8 rom[9])
return 0;
}
-static ssize_t w1_therm_read_bin(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t w1_therm_read(struct device *device,
+ struct device_attribute *attr, char *buf)
{
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
+ struct w1_slave *sl = dev_to_w1_slave(device);
struct w1_master *dev = sl->master;
u8 rom[9], crc, verdict;
int i, max_trying = 10;
+ ssize_t c = PAGE_SIZE;
- mutex_lock(&sl->master->mutex);
+ mutex_lock(&dev->mutex);
- if (off > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
- if (off + count > W1_SLAVE_DATA_SIZE) {
- count = 0;
- goto out;
- }
-
- memset(buf, 0, count);
memset(rom, 0, sizeof(rom));
- count = 0;
verdict = 0;
crc = 0;
@@ -192,15 +183,20 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj,
int count = 0;
unsigned int tm = 750;
+ /* 750ms strong pullup (or delay) after the convert */
+ if (w1_strong_pullup)
+ w1_next_pullup(dev, tm);
w1_write_8(dev, W1_CONVERT_TEMP);
-
- msleep(tm);
+ if (!w1_strong_pullup)
+ msleep(tm);
if (!w1_reset_select_slave(sl)) {
w1_write_8(dev, W1_READ_SCRATCHPAD);
if ((count = w1_read_block(dev, rom, 9)) != 9) {
- dev_warn(&dev->dev, "w1_read_block() returned %d instead of 9.\n", count);
+ dev_warn(device, "w1_read_block() "
+ "returned %u instead of 9.\n",
+ count);
}
crc = w1_calc_crc8(rom, 8);
@@ -215,22 +211,22 @@ static ssize_t w1_therm_read_bin(struct kobject *kobj,
}
for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", rom[i]);
- count += sprintf(buf + count, ": crc=%02x %s\n",
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", rom[i]);
+ c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
crc, (verdict) ? "YES" : "NO");
if (verdict)
memcpy(sl->rom, rom, sizeof(sl->rom));
else
- dev_warn(&dev->dev, "18S20 doesn't respond to CONVERT_TEMP.\n");
+ dev_warn(device, "18S20 doesn't respond to CONVERT_TEMP.\n");
for (i = 0; i < 9; ++i)
- count += sprintf(buf + count, "%02x ", sl->rom[i]);
+ c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ", sl->rom[i]);
- count += sprintf(buf + count, "t=%d\n", w1_convert_temp(rom, sl->family->fid));
-out:
+ c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
+ w1_convert_temp(rom, sl->family->fid));
mutex_unlock(&dev->mutex);
- return count;
+ return PAGE_SIZE - c;
}
static int __init w1_therm_init(void)
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 7293c9b11f9..3b615d4022e 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -46,19 +46,17 @@ MODULE_AUTHOR("Evgeniy Polyakov <johnpol@2ka.mipt.ru>");
MODULE_DESCRIPTION("Driver for 1-wire Dallas network protocol.");
static int w1_timeout = 10;
-static int w1_control_timeout = 1;
int w1_max_slave_count = 10;
int w1_max_slave_ttl = 10;
module_param_named(timeout, w1_timeout, int, 0);
-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_MUTEX(w1_mlock);
LIST_HEAD(w1_masters);
-static struct task_struct *w1_control_thread;
+static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
static int w1_master_match(struct device *dev, struct device_driver *drv)
{
@@ -83,10 +81,10 @@ static void w1_slave_release(struct device *dev)
{
struct w1_slave *sl = dev_to_w1_slave(dev);
- printk("%s: Releasing %s.\n", __func__, sl->name);
+ dev_dbg(dev, "%s: Releasing %s.\n", __func__, sl->name);
while (atomic_read(&sl->refcnt)) {
- printk("Waiting for %s to become free: refcnt=%d.\n",
+ dev_dbg(dev, "Waiting for %s to become free: refcnt=%d.\n",
sl->name, atomic_read(&sl->refcnt));
if (msleep_interruptible(1000))
flush_signals(current);
@@ -105,35 +103,20 @@ static ssize_t w1_slave_read_name(struct device *dev, struct device_attribute *a
return sprintf(buf, "%s\n", sl->name);
}
-static ssize_t w1_slave_read_id(struct kobject *kobj,
- struct bin_attribute *bin_attr,
- char *buf, loff_t off, size_t count)
+static ssize_t w1_slave_read_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct w1_slave *sl = kobj_to_w1_slave(kobj);
-
- if (off > 8) {
- count = 0;
- } else {
- if (off + count > 8)
- count = 8 - off;
-
- memcpy(buf, (u8 *)&sl->reg_num, count);
- }
+ struct w1_slave *sl = dev_to_w1_slave(dev);
+ ssize_t count = sizeof(sl->reg_num);
+ memcpy(buf, (u8 *)&sl->reg_num, count);
return count;
}
static struct device_attribute w1_slave_attr_name =
__ATTR(name, S_IRUGO, w1_slave_read_name, NULL);
-
-static struct bin_attribute w1_slave_attr_bin_id = {
- .attr = {
- .name = "id",
- .mode = S_IRUGO,
- },
- .size = 8,
- .read = w1_slave_read_id,
-};
+static struct device_attribute w1_slave_attr_id =
+ __ATTR(id, S_IRUGO, w1_slave_read_id, NULL);
/* Default family */
@@ -250,11 +233,16 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
struct device_attribute *attr,
const char * buf, size_t count)
{
+ long tmp;
struct w1_master *md = dev_to_w1_master(dev);
+ if (strict_strtol(buf, 0, &tmp) == -EINVAL)
+ return -EINVAL;
+
mutex_lock(&md->mutex);
- md->search_count = simple_strtol(buf, NULL, 0);
+ md->search_count = tmp;
mutex_unlock(&md->mutex);
+ wake_up_process(md->thread);
return count;
}
@@ -273,6 +261,38 @@ static ssize_t w1_master_attribute_show_search(struct device *dev,
return count;
}
+static ssize_t w1_master_attribute_store_pullup(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ long tmp;
+ struct w1_master *md = dev_to_w1_master(dev);
+
+ if (strict_strtol(buf, 0, &tmp) == -EINVAL)
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ md->enable_pullup = tmp;
+ mutex_unlock(&md->mutex);
+ wake_up_process(md->thread);
+
+ return count;
+}
+
+static ssize_t w1_master_attribute_show_pullup(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct w1_master *md = dev_to_w1_master(dev);
+ ssize_t count;
+
+ mutex_lock(&md->mutex);
+ count = sprintf(buf, "%d\n", md->enable_pullup);
+ mutex_unlock(&md->mutex);
+
+ return count;
+}
+
static ssize_t w1_master_attribute_show_pointer(struct device *dev, struct device_attribute *attr, char *buf)
{
struct w1_master *md = dev_to_w1_master(dev);
@@ -324,7 +344,8 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
return count;
}
-static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t w1_master_attribute_show_slaves(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct w1_master *md = dev_to_w1_master(dev);
int c = PAGE_SIZE;
@@ -349,6 +370,135 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device
return PAGE_SIZE - c;
}
+static ssize_t w1_master_attribute_show_add(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int c = PAGE_SIZE;
+ c -= snprintf(buf+PAGE_SIZE - c, c,
+ "write device id xx-xxxxxxxxxxxx to add slave\n");
+ return PAGE_SIZE - c;
+}
+
+static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
+ struct w1_reg_num *rn)
+{
+ unsigned int family;
+ unsigned long long id;
+ int i;
+ u64 rn64_le;
+
+ /* The CRC value isn't read from the user because the sysfs directory
+ * doesn't include it and most messages from the bus search don't
+ * print it either. It would be unreasonable for the user to then
+ * provide it.
+ */
+ const char *error_msg = "bad slave string format, expecting "
+ "ff-dddddddddddd\n";
+
+ if (buf[2] != '-') {
+ dev_err(dev, "%s", error_msg);
+ return -EINVAL;
+ }
+ i = sscanf(buf, "%02x-%012llx", &family, &id);
+ if (i != 2) {
+ dev_err(dev, "%s", error_msg);
+ return -EINVAL;
+ }
+ rn->family = family;
+ rn->id = id;
+
+ rn64_le = cpu_to_le64(*(u64 *)rn);
+ rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
+
+#if 0
+ dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
+ rn->family, (unsigned long long)rn->id, rn->crc);
+#endif
+
+ return 0;
+}
+
+/* Searches the slaves in the w1_master and returns a pointer or NULL.
+ * Note: must hold the mutex
+ */
+static struct w1_slave *w1_slave_search_device(struct w1_master *dev,
+ struct w1_reg_num *rn)
+{
+ struct w1_slave *sl;
+ list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
+ if (sl->reg_num.family == rn->family &&
+ sl->reg_num.id == rn->id &&
+ sl->reg_num.crc == rn->crc) {
+ return sl;
+ }
+ }
+ return NULL;
+}
+
+static ssize_t w1_master_attribute_store_add(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w1_master *md = dev_to_w1_master(dev);
+ struct w1_reg_num rn;
+ struct w1_slave *sl;
+ ssize_t result = count;
+
+ if (w1_atoreg_num(dev, buf, count, &rn))
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ sl = w1_slave_search_device(md, &rn);
+ /* It would be nice to do a targeted search one the one-wire bus
+ * for the new device to see if it is out there or not. But the
+ * current search doesn't support that.
+ */
+ if (sl) {
+ dev_info(dev, "Device %s already exists\n", sl->name);
+ result = -EINVAL;
+ } else {
+ w1_attach_slave_device(md, &rn);
+ }
+ mutex_unlock(&md->mutex);
+
+ return result;
+}
+
+static ssize_t w1_master_attribute_show_remove(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int c = PAGE_SIZE;
+ c -= snprintf(buf+PAGE_SIZE - c, c,
+ "write device id xx-xxxxxxxxxxxx to remove slave\n");
+ return PAGE_SIZE - c;
+}
+
+static ssize_t w1_master_attribute_store_remove(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct w1_master *md = dev_to_w1_master(dev);
+ struct w1_reg_num rn;
+ struct w1_slave *sl;
+ ssize_t result = count;
+
+ if (w1_atoreg_num(dev, buf, count, &rn))
+ return -EINVAL;
+
+ mutex_lock(&md->mutex);
+ sl = w1_slave_search_device(md, &rn);
+ if (sl) {
+ w1_slave_detach(sl);
+ } else {
+ dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
+ (unsigned long long)rn.id);
+ result = -EINVAL;
+ }
+ mutex_unlock(&md->mutex);
+
+ return result;
+}
+
#define W1_MASTER_ATTR_RO(_name, _mode) \
struct device_attribute w1_master_attribute_##_name = \
__ATTR(w1_master_##_name, _mode, \
@@ -368,6 +518,9 @@ static W1_MASTER_ATTR_RO(attempts, S_IRUGO);
static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUGO);
+static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUGO);
static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_name.attr,
@@ -378,6 +531,9 @@ static struct attribute *w1_master_default_attrs[] = {
&w1_master_attribute_timeout.attr,
&w1_master_attribute_pointer.attr,
&w1_master_attribute_search.attr,
+ &w1_master_attribute_pullup.attr,
+ &w1_master_attribute_add.attr,
+ &w1_master_attribute_remove.attr,
NULL
};
@@ -390,7 +546,7 @@ int w1_create_master_attributes(struct w1_master *master)
return sysfs_create_group(&master->dev.kobj, &w1_master_defattr_group);
}
-static void w1_destroy_master_attributes(struct w1_master *master)
+void w1_destroy_master_attributes(struct w1_master *master)
{
sysfs_remove_group(&master->dev.kobj, &w1_master_defattr_group);
}
@@ -479,7 +635,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
}
/* Create "id" entry */
- err = sysfs_create_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+ err = device_create_file(&sl->dev, &w1_slave_attr_id);
if (err < 0) {
dev_err(&sl->dev,
"sysfs file creation for [%s] failed. err=%d\n",
@@ -501,7 +657,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl)
return 0;
out_rem2:
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+ device_remove_file(&sl->dev, &w1_slave_attr_id);
out_rem1:
device_remove_file(&sl->dev, &w1_slave_attr_name);
out_unreg:
@@ -567,7 +723,7 @@ static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn)
return 0;
}
-static void w1_slave_detach(struct w1_slave *sl)
+void w1_slave_detach(struct w1_slave *sl)
{
struct w1_netlink_msg msg;
@@ -583,7 +739,7 @@ static void w1_slave_detach(struct w1_slave *sl)
msg.type = W1_SLAVE_REMOVE;
w1_netlink_send(sl->master, &msg);
- sysfs_remove_bin_file(&sl->dev.kobj, &w1_slave_attr_bin_id);
+ device_remove_file(&sl->dev, &w1_slave_attr_id);
device_remove_file(&sl->dev, &w1_slave_attr_name);
device_unregister(&sl->dev);
@@ -591,24 +747,6 @@ static void w1_slave_detach(struct w1_slave *sl)
kfree(sl);
}
-static struct w1_master *w1_search_master(void *data)
-{
- struct w1_master *dev;
- int found = 0;
-
- mutex_lock(&w1_mlock);
- list_for_each_entry(dev, &w1_masters, w1_master_entry) {
- if (dev->bus_master->data == data) {
- found = 1;
- atomic_inc(&dev->refcnt);
- break;
- }
- }
- mutex_unlock(&w1_mlock);
-
- return (found)?dev:NULL;
-}
-
struct w1_master *w1_search_master_id(u32 id)
{
struct w1_master *dev;
@@ -656,55 +794,56 @@ struct w1_slave *w1_search_slave(struct w1_reg_num *id)
return (found)?sl:NULL;
}
-void w1_reconnect_slaves(struct w1_family *f)
+void w1_reconnect_slaves(struct w1_family *f, int attach)
{
+ struct w1_slave *sl, *sln;
struct w1_master *dev;
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);
+ dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+ "for family %02x.\n", dev->name, f->fid);
+ mutex_lock(&dev->mutex);
+ list_for_each_entry_safe(sl, sln, &dev->slist, w1_slave_entry) {
+ /* If it is a new family, slaves with the default
+ * family driver and are that family will be
+ * connected. If the family is going away, devices
+ * matching that family are reconneced.
+ */
+ if ((attach && sl->family->fid == W1_FAMILY_DEFAULT
+ && sl->reg_num.family == f->fid) ||
+ (!attach && sl->family->fid == f->fid)) {
+ struct w1_reg_num rn;
+
+ memcpy(&rn, &sl->reg_num, sizeof(rn));
+ w1_slave_detach(sl);
+
+ w1_attach_slave_device(dev, &rn);
+ }
+ }
+ dev_dbg(&dev->dev, "Reconnecting slaves in device %s "
+ "has been finished.\n", dev->name);
+ mutex_unlock(&dev->mutex);
}
mutex_unlock(&w1_mlock);
}
-static void w1_slave_found(void *data, u64 rn)
+static void w1_slave_found(struct w1_master *dev, u64 rn)
{
- int slave_count;
struct w1_slave *sl;
- struct list_head *ent;
struct w1_reg_num *tmp;
- struct w1_master *dev;
u64 rn_le = cpu_to_le64(rn);
- dev = w1_search_master(data);
- if (!dev) {
- printk(KERN_ERR "Failed to find w1 master device for data %p, "
- "it is impossible.\n", data);
- return;
- }
+ atomic_inc(&dev->refcnt);
tmp = (struct w1_reg_num *) &rn;
- slave_count = 0;
- list_for_each(ent, &dev->slist) {
-
- sl = list_entry(ent, struct w1_slave, w1_slave_entry);
-
- if (sl->reg_num.family == tmp->family &&
- sl->reg_num.id == tmp->id &&
- sl->reg_num.crc == tmp->crc) {
- set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
- break;
- }
-
- slave_count++;
- }
-
- if (slave_count == dev->slave_count &&
- rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) {
- w1_attach_slave_device(dev, tmp);
+ sl = w1_slave_search_device(dev, tmp);
+ if (sl) {
+ set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags);
+ } else {
+ if (rn && tmp->crc == w1_calc_crc8((u8 *)&rn_le, 7))
+ w1_attach_slave_device(dev, tmp);
}
atomic_dec(&dev->refcnt);
@@ -779,80 +918,20 @@ void w1_search(struct w1_master *dev, u8 search_type, w1_slave_found_callback cb
/* extract the direction taken & update the device number */
tmp64 = (triplet_ret >> 2);
rn |= (tmp64 << i);
+
+ if (kthread_should_stop()) {
+ dev_dbg(&dev->dev, "Abort w1_search\n");
+ return;
+ }
}
if ( (triplet_ret & 0x03) != 0x03 ) {
if ( (desc_bit == last_zero) || (last_zero < 0))
last_device = 1;
desc_bit = last_zero;
- cb(dev->bus_master->data, rn);
- }
- }
-}
-
-static int w1_control(void *data)
-{
- struct w1_slave *sl, *sln;
- struct w1_master *dev, *n;
- int have_to_wait = 0;
-
- set_freezable();
- while (!kthread_should_stop() || have_to_wait) {
- have_to_wait = 0;
-
- try_to_freeze();
- msleep_interruptible(w1_control_timeout * 1000);
-
- list_for_each_entry_safe(dev, n, &w1_masters, w1_master_entry) {
- if (!kthread_should_stop() && !dev->flags)
- continue;
- /*
- * Little race: we can create thread but not set the flag.
- * Get a chance for external process to set flag up.
- */
- if (!dev->initialized) {
- have_to_wait = 1;
- continue;
- }
-
- if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
- set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
-
- mutex_lock(&w1_mlock);
- list_del(&dev->w1_master_entry);
- mutex_unlock(&w1_mlock);
-
- 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);
- 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);
- 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;
-
- memcpy(&rn, &sl->reg_num, sizeof(rn));
- w1_slave_detach(sl);
-
- w1_attach_slave_device(dev, &rn);
- }
- }
- dev_dbg(&dev->dev, "Reconnecting slaves in device %s has been finished.\n", dev->name);
- clear_bit(W1_MASTER_NEED_RECONNECT, &dev->flags);
- mutex_unlock(&dev->mutex);
- }
+ cb(dev, rn);
}
}
-
- return 0;
}
void w1_search_process(struct w1_master *dev, u8 search_type)
@@ -878,23 +957,29 @@ void w1_search_process(struct w1_master *dev, u8 search_type)
int w1_process(void *data)
{
struct w1_master *dev = (struct w1_master *) data;
+ /* As long as w1_timeout is only set by a module parameter the sleep
+ * time can be calculated in jiffies once.
+ */
+ const unsigned long jtime = msecs_to_jiffies(w1_timeout * 1000);
+
+ while (!kthread_should_stop()) {
+ if (dev->search_count) {
+ mutex_lock(&dev->mutex);
+ w1_search_process(dev, W1_SEARCH);
+ mutex_unlock(&dev->mutex);
+ }
- while (!kthread_should_stop() && !test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
try_to_freeze();
- msleep_interruptible(w1_timeout * 1000);
+ __set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop() || test_bit(W1_MASTER_NEED_EXIT, &dev->flags))
+ if (kthread_should_stop())
break;
- if (!dev->initialized)
- continue;
-
- if (dev->search_count == 0)
- continue;
-
- mutex_lock(&dev->mutex);
- w1_search_process(dev, W1_SEARCH);
- mutex_unlock(&dev->mutex);
+ /* Only sleep when the search is active. */
+ if (dev->search_count)
+ schedule_timeout(jtime);
+ else
+ schedule();
}
atomic_dec(&dev->refcnt);
@@ -932,18 +1017,13 @@ static int w1_init(void)
goto err_out_master_unregister;
}
- w1_control_thread = kthread_run(w1_control, NULL, "w1_control");
- if (IS_ERR(w1_control_thread)) {
- retval = PTR_ERR(w1_control_thread);
- printk(KERN_ERR "Failed to create control thread. err=%d\n",
- retval);
- goto err_out_slave_unregister;
- }
-
return 0;
+#if 0
+/* For undoing the slave register if there was a step after it. */
err_out_slave_unregister:
driver_unregister(&w1_slave_driver);
+#endif
err_out_master_unregister:
driver_unregister(&w1_master_driver);
@@ -959,13 +1039,12 @@ static void w1_fini(void)
{
struct w1_master *dev;
+ /* Set netlink removal messages and some cleanup */
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);
driver_unregister(&w1_master_driver);
bus_unregister(&w1_bus_type);
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h
index f1df5343f4a..cdaa6fffbfc 100644
--- a/drivers/w1/w1.h
+++ b/drivers/w1/w1.h
@@ -46,7 +46,6 @@ struct w1_reg_num
#include "w1_family.h"
#define W1_MAXNAMELEN 32
-#define W1_SLAVE_DATA_SIZE 128
#define W1_SEARCH 0xF0
#define W1_ALARM_SEARCH 0xEC
@@ -77,7 +76,7 @@ struct w1_slave
struct completion released;
};
-typedef void (* w1_slave_found_callback)(void *, u64);
+typedef void (*w1_slave_found_callback)(struct w1_master *, u64);
/**
@@ -142,12 +141,18 @@ struct w1_bus_master
*/
u8 (*reset_bus)(void *);
- /** Really nice hardware can handles the different types of ROM search */
- void (*search)(void *, u8, w1_slave_found_callback);
-};
+ /**
+ * Put out a strong pull-up pulse of the specified duration.
+ * @return -1=Error, 0=completed
+ */
+ u8 (*set_pullup)(void *, int);
-#define W1_MASTER_NEED_EXIT 0
-#define W1_MASTER_NEED_RECONNECT 1
+ /** Really nice hardware can handles the different types of ROM search
+ * w1_master* is passed to the slave found callback.
+ */
+ void (*search)(void *, struct w1_master *,
+ u8, w1_slave_found_callback);
+};
struct w1_master
{
@@ -167,7 +172,10 @@ struct w1_master
void *priv;
int priv_size;
- long flags;
+ /** 5V strong pullup enabled flag, 1 enabled, zero disabled. */
+ int enable_pullup;
+ /** 5V strong pullup duration in milliseconds, zero disabled. */
+ int pullup_duration;
struct task_struct *thread;
struct mutex mutex;
@@ -181,12 +189,21 @@ struct w1_master
};
int w1_create_master_attributes(struct w1_master *);
+void w1_destroy_master_attributes(struct w1_master *master);
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);
+/* Disconnect and reconnect devices in the given family. Used for finding
+ * unclaimed devices after a family has been registered or releasing devices
+ * after a family has been unregistered. Set attach to 1 when a new family
+ * has just been registered, to 0 when it has been unregistered.
+ */
+void w1_reconnect_slaves(struct w1_family *f, int attach);
+void w1_slave_detach(struct w1_slave *sl);
+
u8 w1_triplet(struct w1_master *dev, int bdir);
void w1_write_8(struct w1_master *, u8);
int w1_reset_bus(struct w1_master *);
@@ -194,6 +211,7 @@ 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);
+void w1_next_pullup(struct w1_master *, int);
static inline struct w1_slave* dev_to_w1_slave(struct device *dev)
{
diff --git a/drivers/w1/w1_family.c b/drivers/w1/w1_family.c
index a3c95bd6890..4a099041f28 100644
--- a/drivers/w1/w1_family.c
+++ b/drivers/w1/w1_family.c
@@ -48,12 +48,12 @@ int w1_register_family(struct w1_family *newf)
if (!ret) {
atomic_set(&newf->refcnt, 0);
- newf->need_exit = 0;
list_add_tail(&newf->family_entry, &w1_families);
}
spin_unlock(&w1_flock);
- w1_reconnect_slaves(newf);
+ /* check default devices against the new set of drivers */
+ w1_reconnect_slaves(newf, 1);
return ret;
}
@@ -72,11 +72,11 @@ void w1_unregister_family(struct w1_family *fent)
break;
}
}
-
- fent->need_exit = 1;
-
spin_unlock(&w1_flock);
+ /* deatch devices using this family code */
+ w1_reconnect_slaves(fent, 0);
+
while (atomic_read(&fent->refcnt)) {
printk(KERN_INFO "Waiting for family %u to become free: refcnt=%d.\n",
fent->fid, atomic_read(&fent->refcnt));
@@ -109,8 +109,7 @@ struct w1_family * w1_family_registered(u8 fid)
static void __w1_family_put(struct w1_family *f)
{
- if (atomic_dec_and_test(&f->refcnt))
- f->need_exit = 1;
+ atomic_dec(&f->refcnt);
}
void w1_family_put(struct w1_family *f)
diff --git a/drivers/w1/w1_family.h b/drivers/w1/w1_family.h
index ef1e1dafa19..3ca1b9298f2 100644
--- a/drivers/w1/w1_family.h
+++ b/drivers/w1/w1_family.h
@@ -33,6 +33,7 @@
#define W1_THERM_DS1822 0x22
#define W1_EEPROM_DS2433 0x23
#define W1_THERM_DS18B20 0x28
+#define W1_EEPROM_DS2431 0x2D
#define W1_FAMILY_DS2760 0x30
#define MAXNAMELEN 32
@@ -53,7 +54,6 @@ struct w1_family
struct w1_family_ops *fops;
atomic_t refcnt;
- u8 need_exit;
};
extern spinlock_t w1_flock;
@@ -63,6 +63,5 @@ void __w1_family_get(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 6840dfebe4d..a3a54567bfb 100644
--- a/drivers/w1/w1_int.c
+++ b/drivers/w1/w1_int.c
@@ -29,7 +29,11 @@
#include "w1_netlink.h"
#include "w1_int.h"
-static u32 w1_ids = 1;
+static int w1_search_count = -1; /* Default is continual scan */
+module_param_named(search_count, w1_search_count, int, 0);
+
+static int w1_enable_pullup = 1;
+module_param_named(enable_pullup, w1_enable_pullup, int, 0);
static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
struct device_driver *driver,
@@ -59,8 +63,12 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl,
dev->initialized = 0;
dev->id = id;
dev->slave_ttl = slave_ttl;
- dev->search_count = -1; /* continual scan */
+ dev->search_count = w1_search_count;
+ dev->enable_pullup = w1_enable_pullup;
+ /* 1 for w1_process to decrement
+ * 1 for __w1_remove_master_device to decrement
+ */
atomic_set(&dev->refcnt, 2);
INIT_LIST_HEAD(&dev->slist);
@@ -93,9 +101,10 @@ static void w1_free_dev(struct w1_master *dev)
int w1_add_master_device(struct w1_bus_master *master)
{
- struct w1_master *dev;
+ struct w1_master *dev, *entry;
int retval = 0;
struct w1_netlink_msg msg;
+ int id, found;
/* validate minimum functionality */
if (!(master->touch_bit && master->reset_bus) &&
@@ -104,10 +113,50 @@ int w1_add_master_device(struct w1_bus_master *master)
printk(KERN_ERR "w1_add_master_device: invalid function set\n");
return(-EINVAL);
}
+ /* While it would be electrically possible to make a device that
+ * generated a strong pullup in bit bang mode, only hardare that
+ * controls 1-wire time frames are even expected to support a strong
+ * pullup. w1_io.c would need to support calling set_pullup before
+ * the last write_bit operation of a w1_write_8 which it currently
+ * doesn't.
+ */
+ if (!master->write_byte && !master->touch_bit && master->set_pullup) {
+ printk(KERN_ERR "w1_add_master_device: set_pullup requires "
+ "write_byte or touch_bit, disabling\n");
+ master->set_pullup = NULL;
+ }
+
+ /* Lock until the device is added (or not) to w1_masters. */
+ mutex_lock(&w1_mlock);
+ /* Search for the first available id (starting at 1). */
+ id = 0;
+ do {
+ ++id;
+ found = 0;
+ list_for_each_entry(entry, &w1_masters, w1_master_entry) {
+ if (entry->id == id) {
+ found = 1;
+ break;
+ }
+ }
+ } while (found);
- dev = w1_alloc_dev(w1_ids++, w1_max_slave_count, w1_max_slave_ttl, &w1_master_driver, &w1_master_device);
- if (!dev)
+ dev = w1_alloc_dev(id, w1_max_slave_count, w1_max_slave_ttl,
+ &w1_master_driver, &w1_master_device);
+ if (!dev) {
+ mutex_unlock(&w1_mlock);
return -ENOMEM;
+ }
+
+ retval = w1_create_master_attributes(dev);
+ if (retval) {
+ mutex_unlock(&w1_mlock);
+ goto err_out_free_dev;
+ }
+
+ memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
+
+ dev->initialized = 1;
dev->thread = kthread_run(&w1_process, dev, "%s", dev->name);
if (IS_ERR(dev->thread)) {
@@ -115,18 +164,10 @@ int w1_add_master_device(struct w1_bus_master *master)
dev_err(&dev->dev,
"Failed to create new kernel thread. err=%d\n",
retval);
- goto err_out_free_dev;
+ mutex_unlock(&w1_mlock);
+ goto err_out_rm_attr;
}
- retval = w1_create_master_attributes(dev);
- if (retval)
- goto err_out_kill_thread;
-
- memcpy(dev->bus_master, master, sizeof(struct w1_bus_master));
-
- dev->initialized = 1;
-
- mutex_lock(&w1_mlock);
list_add(&dev->w1_master_entry, &w1_masters);
mutex_unlock(&w1_mlock);
@@ -137,8 +178,12 @@ int w1_add_master_device(struct w1_bus_master *master)
return 0;
+#if 0 /* Thread cleanup code, not required currently. */
err_out_kill_thread:
kthread_stop(dev->thread);
+#endif
+err_out_rm_attr:
+ w1_destroy_master_attributes(dev);
err_out_free_dev:
w1_free_dev(dev);
@@ -148,10 +193,21 @@ err_out_free_dev:
void __w1_remove_master_device(struct w1_master *dev)
{
struct w1_netlink_msg msg;
+ struct w1_slave *sl, *sln;
- set_bit(W1_MASTER_NEED_EXIT, &dev->flags);
kthread_stop(dev->thread);
+ mutex_lock(&w1_mlock);
+ list_del(&dev->w1_master_entry);
+ mutex_unlock(&w1_mlock);
+
+ 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);
+ mutex_unlock(&dev->mutex);
+ atomic_dec(&dev->refcnt);
+
while (atomic_read(&dev->refcnt)) {
dev_info(&dev->dev, "Waiting for %s to become free: refcnt=%d.\n",
dev->name, atomic_read(&dev->refcnt));
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c
index 30b6fbf83bd..f4f82f1f486 100644
--- a/drivers/w1/w1_io.c
+++ b/drivers/w1/w1_io.c
@@ -93,6 +93,40 @@ static void w1_write_bit(struct w1_master *dev, int bit)
}
/**
+ * Pre-write operation, currently only supporting strong pullups.
+ * Program the hardware for a strong pullup, if one has been requested and
+ * the hardware supports it.
+ *
+ * @param dev the master device
+ */
+static void w1_pre_write(struct w1_master *dev)
+{
+ if (dev->pullup_duration &&
+ dev->enable_pullup && dev->bus_master->set_pullup) {
+ dev->bus_master->set_pullup(dev->bus_master->data,
+ dev->pullup_duration);
+ }
+}
+
+/**
+ * Post-write operation, currently only supporting strong pullups.
+ * If a strong pullup was requested, clear it if the hardware supports
+ * them, or execute the delay otherwise, in either case clear the request.
+ *
+ * @param dev the master device
+ */
+static void w1_post_write(struct w1_master *dev)
+{
+ if (dev->pullup_duration) {
+ if (dev->enable_pullup && dev->bus_master->set_pullup)
+ dev->bus_master->set_pullup(dev->bus_master->data, 0);
+ else
+ msleep(dev->pullup_duration);
+ dev->pullup_duration = 0;
+ }
+}
+
+/**
* Writes 8 bits.
*
* @param dev the master device
@@ -102,11 +136,17 @@ void w1_write_8(struct w1_master *dev, u8 byte)
{
int i;
- if (dev->bus_master->write_byte)
+ if (dev->bus_master->write_byte) {
+ w1_pre_write(dev);
dev->bus_master->write_byte(dev->bus_master->data, byte);
+ }
else
- for (i = 0; i < 8; ++i)
+ for (i = 0; i < 8; ++i) {
+ if (i == 7)
+ w1_pre_write(dev);
w1_touch_bit(dev, (byte >> i) & 0x1);
+ }
+ w1_post_write(dev);
}
EXPORT_SYMBOL_GPL(w1_write_8);
@@ -203,11 +243,14 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len)
{
int i;
- if (dev->bus_master->write_block)
+ if (dev->bus_master->write_block) {
+ w1_pre_write(dev);
dev->bus_master->write_block(dev->bus_master->data, buf, len);
+ }
else
for (i = 0; i < len; ++i)
- w1_write_8(dev, buf[i]);
+ w1_write_8(dev, buf[i]); /* calls w1_pre_write */
+ w1_post_write(dev);
}
EXPORT_SYMBOL_GPL(w1_write_block);
@@ -250,12 +293,24 @@ int w1_reset_bus(struct w1_master *dev)
result = dev->bus_master->reset_bus(dev->bus_master->data) & 0x1;
else {
dev->bus_master->write_bit(dev->bus_master->data, 0);
+ /* minimum 480, max ? us
+ * be nice and sleep, except 18b20 spec lists 960us maximum,
+ * so until we can sleep with microsecond accuracy, spin.
+ * Feel free to come up with some other way to give up the
+ * cpu for such a short amount of time AND get it back in
+ * the maximum amount of time.
+ */
w1_delay(480);
dev->bus_master->write_bit(dev->bus_master->data, 1);
w1_delay(70);
result = dev->bus_master->read_bit(dev->bus_master->data) & 0x1;
- w1_delay(410);
+ /* minmum 70 (above) + 410 = 480 us
+ * There aren't any timing requirements between a reset and
+ * the following transactions. Sleeping is safe here.
+ */
+ /* w1_delay(410); min required time */
+ msleep(1);
}
return result;
@@ -277,7 +332,8 @@ void w1_search_devices(struct w1_master *dev, u8 search_type, w1_slave_found_cal
{
dev->attempts++;
if (dev->bus_master->search)
- dev->bus_master->search(dev->bus_master->data, search_type, cb);
+ dev->bus_master->search(dev->bus_master->data, dev,
+ search_type, cb);
else
w1_search(dev, search_type, cb);
}
@@ -305,3 +361,20 @@ int w1_reset_select_slave(struct w1_slave *sl)
return 0;
}
EXPORT_SYMBOL_GPL(w1_reset_select_slave);
+
+/**
+ * Put out a strong pull-up of the specified duration after the next write
+ * operation. Not all hardware supports strong pullups. Hardware that
+ * doesn't support strong pullups will sleep for the given time after the
+ * write operation without a strong pullup. This is a one shot request for
+ * the next write, specifying zero will clear a previous request.
+ * The w1 master lock must be held.
+ *
+ * @param delay time in milliseconds
+ * @return 0=success, anything else=error
+ */
+void w1_next_pullup(struct w1_master *dev, int delay)
+{
+ dev->pullup_duration = delay;
+}
+EXPORT_SYMBOL_GPL(w1_next_pullup);
diff --git a/fs/Kconfig b/fs/Kconfig
index f54a157a029..9e9d70c02a0 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -220,17 +220,16 @@ config JBD
tristate
help
This is a generic journalling layer for block devices. It is
- currently used by the ext3 and OCFS2 file systems, but it could
- also be used to add journal support to other file systems or block
+ currently used by the ext3 file system, but it could also be
+ used to add journal support to other file systems or block
devices such as RAID or LVM.
- If you are using the ext3 or OCFS2 file systems, you need to
- say Y here. If you are not using ext3 OCFS2 then you will probably
- want to say N.
+ If you are using the ext3 file system, you need to say Y here.
+ If you are not using ext3 then you will probably want to say N.
To compile this device as a module, choose M here: the module will be
- called jbd. If you are compiling ext3 or OCFS2 into the kernel,
- you cannot compile this code as a module.
+ called jbd. If you are compiling ext3 into the kernel, you
+ cannot compile this code as a module.
config JBD_DEBUG
bool "JBD (ext3) debugging support"
@@ -254,15 +253,16 @@ config JBD2
help
This is a generic journaling layer for block devices that support
both 32-bit and 64-bit block numbers. It is currently used by
- the ext4 filesystem, but it could also be used to add
+ the ext4 and OCFS2 filesystems, but it could also be used to add
journal support to other file systems or block devices such
as RAID or LVM.
- If you are using ext4, you need to say Y here. If you are not
- using ext4 then you will probably want to say N.
+ If you are using ext4 or OCFS2, you need to say Y here.
+ If you are not using ext4 or OCFS2 then you will
+ probably want to say N.
To compile this device as a module, choose M here. The module will be
- called jbd2. If you are compiling ext4 into the kernel,
+ called jbd2. If you are compiling ext4 or OCFS2 into the kernel,
you cannot compile this code as a module.
config JBD2_DEBUG
@@ -433,6 +433,14 @@ config FS_POSIX_ACL
bool
default n
+config FILE_LOCKING
+ bool "Enable POSIX file locking API" if EMBEDDED
+ default y
+ help
+ This option enables standard file locking support, required
+ for filesystems like NFS and for the flock() system
+ call. Disabling this option saves about 11k.
+
source "fs/xfs/Kconfig"
source "fs/gfs2/Kconfig"
@@ -440,7 +448,7 @@ config OCFS2_FS
tristate "OCFS2 file system support"
depends on NET && SYSFS
select CONFIGFS_FS
- select JBD
+ select JBD2
select CRC32
help
OCFS2 is a general purpose extent based shared disk cluster file
@@ -511,6 +519,16 @@ config OCFS2_DEBUG_FS
this option for debugging only as it is likely to decrease
performance of the filesystem.
+config OCFS2_COMPAT_JBD
+ bool "Use JBD for compatibility"
+ depends on OCFS2_FS
+ default n
+ select JBD
+ help
+ The ocfs2 filesystem now uses JBD2 for its journalling. JBD2
+ is backwards compatible with JBD. It is safe to say N here.
+ However, if you really want to use the original JBD, say Y here.
+
endif # BLOCK
config DNOTIFY
@@ -1779,6 +1797,28 @@ config SUNRPC_XPRT_RDMA
If unsure, say N.
+config SUNRPC_REGISTER_V4
+ bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
+ depends on SUNRPC && EXPERIMENTAL
+ default n
+ help
+ Sun added support for registering RPC services at an IPv6
+ address by creating two new versions of the rpcbind protocol
+ (RFC 1833).
+
+ This option enables support in the kernel RPC server for
+ registering kernel RPC services via version 4 of the rpcbind
+ protocol. If you enable this option, you must run a portmapper
+ daemon that supports rpcbind protocol version 4.
+
+ Serving NFS over IPv6 from knfsd (the kernel's NFS server)
+ requires that you enable this option and use a portmapper that
+ supports rpcbind version 4.
+
+ If unsure, say N to get traditional behavior (register kernel
+ RPC services using only rpcbind version 2). Distributions
+ using the legacy Linux portmapper daemon must say N here.
+
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 17c9c5ec14c..801db134181 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -25,7 +25,7 @@ config BINFMT_ELF
config COMPAT_BINFMT_ELF
bool
- depends on COMPAT && MMU
+ depends on COMPAT && BINFMT_ELF
config BINFMT_ELF_FDPIC
bool "Kernel support for FDPIC ELF binaries"
diff --git a/fs/Makefile b/fs/Makefile
index de404b00eb0..d0c69f57e5b 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -7,8 +7,8 @@
obj-y := open.o read_write.o file_table.o super.o \
char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
- ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
- attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
+ ioctl.o readdir.o select.o fifo.o dcache.o inode.o \
+ attr.o bad_inode.o file.o filesystems.o namespace.o \
seq_file.o xattr.o libfs.o fs-writeback.o \
pnode.o drop_caches.o splice.o sync.o utimes.o \
stack.o
@@ -27,6 +27,8 @@ obj-$(CONFIG_ANON_INODES) += anon_inodes.o
obj-$(CONFIG_SIGNALFD) += signalfd.o
obj-$(CONFIG_TIMERFD) += timerfd.o
obj-$(CONFIG_EVENTFD) += eventfd.o
+obj-$(CONFIG_AIO) += aio.o
+obj-$(CONFIG_FILE_LOCKING) += locks.o
obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
nfsd-$(CONFIG_NFSD) := nfsctl.o
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 525f7c56e06..a3901769a96 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -50,8 +50,8 @@ const struct address_space_operations afs_fs_aops = {
.launder_page = afs_launder_page,
.releasepage = afs_releasepage,
.invalidatepage = afs_invalidatepage,
- .prepare_write = afs_prepare_write,
- .commit_write = afs_commit_write,
+ .write_begin = afs_write_begin,
+ .write_end = afs_write_end,
.writepage = afs_writepage,
.writepages = afs_writepages,
};
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index 3cb6920ff30..67f259d99cd 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -728,8 +728,12 @@ extern int afs_volume_release_fileserver(struct afs_vnode *,
*/
extern int afs_set_page_dirty(struct page *);
extern void afs_put_writeback(struct afs_writeback *);
-extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned);
-extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned);
+extern int afs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata);
+extern int afs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata);
extern int afs_writepage(struct page *, struct writeback_control *);
extern int afs_writepages(struct address_space *, struct writeback_control *);
extern int afs_write_inode(struct inode *, int);
diff --git a/fs/afs/write.c b/fs/afs/write.c
index 065b4e10681..d6b85dab35f 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -84,15 +84,23 @@ void afs_put_writeback(struct afs_writeback *wb)
* partly or wholly fill a page that's under preparation for writing
*/
static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
- unsigned start, unsigned len, struct page *page)
+ loff_t pos, unsigned len, struct page *page)
{
+ loff_t i_size;
+ unsigned eof;
int ret;
- _enter(",,%u,%u", start, len);
+ _enter(",,%llu,%u", (unsigned long long)pos, len);
- ASSERTCMP(start + len, <=, PAGE_SIZE);
+ ASSERTCMP(len, <=, PAGE_CACHE_SIZE);
- ret = afs_vnode_fetch_data(vnode, key, start, len, page);
+ i_size = i_size_read(&vnode->vfs_inode);
+ if (pos + len > i_size)
+ eof = i_size;
+ else
+ eof = PAGE_CACHE_SIZE;
+
+ ret = afs_vnode_fetch_data(vnode, key, 0, eof, page);
if (ret < 0) {
if (ret == -ENOENT) {
_debug("got NOENT from server"
@@ -107,109 +115,55 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
}
/*
- * prepare a page for being written to
- */
-static int afs_prepare_page(struct afs_vnode *vnode, struct page *page,
- struct key *key, unsigned offset, unsigned to)
-{
- unsigned eof, tail, start, stop, len;
- loff_t i_size, pos;
- void *p;
- int ret;
-
- _enter("");
-
- if (offset == 0 && to == PAGE_SIZE)
- return 0;
-
- p = kmap_atomic(page, KM_USER0);
-
- i_size = i_size_read(&vnode->vfs_inode);
- pos = (loff_t) page->index << PAGE_SHIFT;
- if (pos >= i_size) {
- /* partial write, page beyond EOF */
- _debug("beyond");
- if (offset > 0)
- memset(p, 0, offset);
- if (to < PAGE_SIZE)
- memset(p + to, 0, PAGE_SIZE - to);
- kunmap_atomic(p, KM_USER0);
- return 0;
- }
-
- if (i_size - pos >= PAGE_SIZE) {
- /* partial write, page entirely before EOF */
- _debug("before");
- tail = eof = PAGE_SIZE;
- } else {
- /* partial write, page overlaps EOF */
- eof = i_size - pos;
- _debug("overlap %u", eof);
- tail = max(eof, to);
- if (tail < PAGE_SIZE)
- memset(p + tail, 0, PAGE_SIZE - tail);
- if (offset > eof)
- memset(p + eof, 0, PAGE_SIZE - eof);
- }
-
- kunmap_atomic(p, KM_USER0);
-
- ret = 0;
- if (offset > 0 || eof > to) {
- /* need to fill one or two bits that aren't going to be written
- * (cover both fillers in one read if there are two) */
- start = (offset > 0) ? 0 : to;
- stop = (eof > to) ? eof : offset;
- len = stop - start;
- _debug("wr=%u-%u av=0-%u rd=%u@%u",
- offset, to, eof, start, len);
- ret = afs_fill_page(vnode, key, start, len, page);
- }
-
- _leave(" = %d", ret);
- return ret;
-}
-
-/*
* prepare to perform part of a write to a page
- * - the caller holds the page locked, preventing it from being written out or
- * modified by anyone else
*/
-int afs_prepare_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
+int afs_write_begin(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
{
struct afs_writeback *candidate, *wb;
struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
+ struct page *page;
struct key *key = file->private_data;
- pgoff_t index;
+ unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+ unsigned to = from + len;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
int ret;
_enter("{%x:%u},{%lx},%u,%u",
- vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+ vnode->fid.vid, vnode->fid.vnode, index, from, to);
candidate = kzalloc(sizeof(*candidate), GFP_KERNEL);
if (!candidate)
return -ENOMEM;
candidate->vnode = vnode;
- candidate->first = candidate->last = page->index;
- candidate->offset_first = offset;
+ candidate->first = candidate->last = index;
+ candidate->offset_first = from;
candidate->to_last = to;
candidate->usage = 1;
candidate->state = AFS_WBACK_PENDING;
init_waitqueue_head(&candidate->waitq);
+ page = __grab_cache_page(mapping, index);
+ if (!page) {
+ kfree(candidate);
+ return -ENOMEM;
+ }
+ *pagep = page;
+ /* page won't leak in error case: it eventually gets cleaned off LRU */
+
if (!PageUptodate(page)) {
_debug("not up to date");
- ret = afs_prepare_page(vnode, page, key, offset, to);
+ ret = afs_fill_page(vnode, key, pos, len, page);
if (ret < 0) {
kfree(candidate);
_leave(" = %d [prep]", ret);
return ret;
}
+ SetPageUptodate(page);
}
try_again:
- index = page->index;
spin_lock(&vnode->writeback_lock);
/* see if this page is already pending a writeback under a suitable key
@@ -242,8 +196,8 @@ try_again:
subsume_in_current_wb:
_debug("subsume");
ASSERTRANGE(wb->first, <=, index, <=, wb->last);
- if (index == wb->first && offset < wb->offset_first)
- wb->offset_first = offset;
+ if (index == wb->first && from < wb->offset_first)
+ wb->offset_first = from;
if (index == wb->last && to > wb->to_last)
wb->to_last = to;
spin_unlock(&vnode->writeback_lock);
@@ -289,17 +243,17 @@ flush_conflicting_wb:
/*
* finalise part of a write to a page
*/
-int afs_commit_write(struct file *file, struct page *page,
- unsigned offset, unsigned to)
+int afs_write_end(struct file *file, struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode);
loff_t i_size, maybe_i_size;
- _enter("{%x:%u},{%lx},%u,%u",
- vnode->fid.vid, vnode->fid.vnode, page->index, offset, to);
+ _enter("{%x:%u},{%lx}",
+ vnode->fid.vid, vnode->fid.vnode, page->index);
- maybe_i_size = (loff_t) page->index << PAGE_SHIFT;
- maybe_i_size += to;
+ maybe_i_size = pos + copied;
i_size = i_size_read(&vnode->vfs_inode);
if (maybe_i_size > i_size) {
@@ -310,12 +264,13 @@ int afs_commit_write(struct file *file, struct page *page,
spin_unlock(&vnode->writeback_lock);
}
- SetPageUptodate(page);
set_page_dirty(page);
if (PageDirty(page))
_debug("dirtied");
+ unlock_page(page);
+ page_cache_release(page);
- return 0;
+ return copied;
}
/*
diff --git a/fs/autofs4/Makefile b/fs/autofs4/Makefile
index f2c3b79e94d..a811c1f7d9a 100644
--- a/fs/autofs4/Makefile
+++ b/fs/autofs4/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_AUTOFS4_FS) += autofs4.o
-autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o
+autofs4-objs := init.o inode.o root.o symlink.o waitq.o expire.o dev-ioctl.o
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 69a2f5c9231..e0f16da00e5 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -14,6 +14,7 @@
/* Internal header file for autofs */
#include <linux/auto_fs4.h>
+#include <linux/auto_dev-ioctl.h>
#include <linux/mutex.h>
#include <linux/list.h>
@@ -21,6 +22,11 @@
#define AUTOFS_IOC_FIRST AUTOFS_IOC_READY
#define AUTOFS_IOC_COUNT 32
+#define AUTOFS_DEV_IOCTL_IOC_FIRST (AUTOFS_DEV_IOCTL_VERSION)
+#define AUTOFS_DEV_IOCTL_IOC_COUNT (AUTOFS_IOC_COUNT - 11)
+
+#define AUTOFS_TYPE_TRIGGER (AUTOFS_TYPE_DIRECT|AUTOFS_TYPE_OFFSET)
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/time.h>
@@ -35,11 +41,27 @@
/* #define DEBUG */
#ifdef DEBUG
-#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __func__ , ##args); } while(0)
+#define DPRINTK(fmt, args...) \
+do { \
+ printk(KERN_DEBUG "pid %d: %s: " fmt "\n", \
+ current->pid, __func__, ##args); \
+} while (0)
#else
-#define DPRINTK(fmt,args...) do {} while(0)
+#define DPRINTK(fmt, args...) do {} while (0)
#endif
+#define AUTOFS_WARN(fmt, args...) \
+do { \
+ printk(KERN_WARNING "pid %d: %s: " fmt "\n", \
+ current->pid, __func__, ##args); \
+} while (0)
+
+#define AUTOFS_ERROR(fmt, args...) \
+do { \
+ printk(KERN_ERR "pid %d: %s: " fmt "\n", \
+ current->pid, __func__, ##args); \
+} while (0)
+
/* Unified info structure. This is pointed to by both the dentry and
inode structures. Each file in the filesystem has an instance of this
structure. It holds a reference to the dentry, so dentries are never
@@ -61,6 +83,9 @@ struct autofs_info {
unsigned long last_used;
atomic_t count;
+ uid_t uid;
+ gid_t gid;
+
mode_t mode;
size_t size;
@@ -92,10 +117,6 @@ struct autofs_wait_queue {
#define AUTOFS_SBI_MAGIC 0x6d4a556d
-#define AUTOFS_TYPE_INDIRECT 0x0001
-#define AUTOFS_TYPE_DIRECT 0x0002
-#define AUTOFS_TYPE_OFFSET 0x0004
-
struct autofs_sb_info {
u32 magic;
int pipefd;
@@ -169,6 +190,17 @@ int autofs4_expire_run(struct super_block *, struct vfsmount *,
struct autofs_packet_expire __user *);
int autofs4_expire_multi(struct super_block *, struct vfsmount *,
struct autofs_sb_info *, int __user *);
+struct dentry *autofs4_expire_direct(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi, int how);
+struct dentry *autofs4_expire_indirect(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi, int how);
+
+/* Device node initialization */
+
+int autofs_dev_ioctl_init(void);
+void autofs_dev_ioctl_exit(void);
/* Operations structures */
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c
new file mode 100644
index 00000000000..625abf5422e
--- /dev/null
+++ b/fs/autofs4/dev-ioctl.c
@@ -0,0 +1,863 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/namei.h>
+#include <linux/fcntl.h>
+#include <linux/file.h>
+#include <linux/fdtable.h>
+#include <linux/sched.h>
+#include <linux/compat.h>
+#include <linux/syscalls.h>
+#include <linux/smp_lock.h>
+#include <linux/magic.h>
+#include <linux/dcache.h>
+#include <linux/uaccess.h>
+
+#include "autofs_i.h"
+
+/*
+ * This module implements an interface for routing autofs ioctl control
+ * commands via a miscellaneous device file.
+ *
+ * The alternate interface is needed because we need to be able open
+ * an ioctl file descriptor on an autofs mount that may be covered by
+ * another mount. This situation arises when starting automount(8)
+ * or other user space daemon which uses direct mounts or offset
+ * mounts (used for autofs lazy mount/umount of nested mount trees),
+ * which have been left busy at at service shutdown.
+ */
+
+#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl)
+
+typedef int (*ioctl_fn)(struct file *, struct autofs_sb_info *,
+ struct autofs_dev_ioctl *);
+
+static int check_name(const char *name)
+{
+ if (!strchr(name, '/'))
+ return -EINVAL;
+ return 0;
+}
+
+/*
+ * Check a string doesn't overrun the chunk of
+ * memory we copied from user land.
+ */
+static int invalid_str(char *str, void *end)
+{
+ while ((void *) str <= end)
+ if (!*str++)
+ return 0;
+ return -EINVAL;
+}
+
+/*
+ * Check that the user compiled against correct version of autofs
+ * misc device code.
+ *
+ * As well as checking the version compatibility this always copies
+ * the kernel interface version out.
+ */
+static int check_dev_ioctl_version(int cmd, struct autofs_dev_ioctl *param)
+{
+ int err = 0;
+
+ if ((AUTOFS_DEV_IOCTL_VERSION_MAJOR != param->ver_major) ||
+ (AUTOFS_DEV_IOCTL_VERSION_MINOR < param->ver_minor)) {
+ AUTOFS_WARN("ioctl control interface version mismatch: "
+ "kernel(%u.%u), user(%u.%u), cmd(%d)",
+ AUTOFS_DEV_IOCTL_VERSION_MAJOR,
+ AUTOFS_DEV_IOCTL_VERSION_MINOR,
+ param->ver_major, param->ver_minor, cmd);
+ err = -EINVAL;
+ }
+
+ /* Fill in the kernel version. */
+ param->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+ param->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+
+ return err;
+}
+
+/*
+ * Copy parameter control struct, including a possible path allocated
+ * at the end of the struct.
+ */
+static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *in)
+{
+ struct autofs_dev_ioctl tmp, *ads;
+
+ if (copy_from_user(&tmp, in, sizeof(tmp)))
+ return ERR_PTR(-EFAULT);
+
+ if (tmp.size < sizeof(tmp))
+ return ERR_PTR(-EINVAL);
+
+ ads = kmalloc(tmp.size, GFP_KERNEL);
+ if (!ads)
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(ads, in, tmp.size)) {
+ kfree(ads);
+ return ERR_PTR(-EFAULT);
+ }
+
+ return ads;
+}
+
+static inline void free_dev_ioctl(struct autofs_dev_ioctl *param)
+{
+ kfree(param);
+ return;
+}
+
+/*
+ * Check sanity of parameter control fields and if a path is present
+ * check that it has a "/" and is terminated.
+ */
+static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
+{
+ int err = -EINVAL;
+
+ if (check_dev_ioctl_version(cmd, param)) {
+ AUTOFS_WARN("invalid device control module version "
+ "supplied for cmd(0x%08x)", cmd);
+ goto out;
+ }
+
+ if (param->size > sizeof(*param)) {
+ err = check_name(param->path);
+ if (err) {
+ AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
+ cmd);
+ goto out;
+ }
+
+ err = invalid_str(param->path,
+ (void *) ((size_t) param + param->size));
+ if (err) {
+ AUTOFS_WARN("invalid path supplied for cmd(0x%08x)",
+ cmd);
+ goto out;
+ }
+ }
+
+ err = 0;
+out:
+ return err;
+}
+
+/*
+ * Get the autofs super block info struct from the file opened on
+ * the autofs mount point.
+ */
+static struct autofs_sb_info *autofs_dev_ioctl_sbi(struct file *f)
+{
+ struct autofs_sb_info *sbi = NULL;
+ struct inode *inode;
+
+ if (f) {
+ inode = f->f_path.dentry->d_inode;
+ sbi = autofs4_sbi(inode->i_sb);
+ }
+ return sbi;
+}
+
+/* Return autofs module protocol version */
+static int autofs_dev_ioctl_protover(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ param->arg1 = sbi->version;
+ return 0;
+}
+
+/* Return autofs module protocol sub version */
+static int autofs_dev_ioctl_protosubver(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ param->arg1 = sbi->sub_version;
+ return 0;
+}
+
+/*
+ * Walk down the mount stack looking for an autofs mount that
+ * has the requested device number (aka. new_encode_dev(sb->s_dev).
+ */
+static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno)
+{
+ struct dentry *dentry;
+ struct inode *inode;
+ struct super_block *sb;
+ dev_t s_dev;
+ unsigned int err;
+
+ err = -ENOENT;
+
+ /* Lookup the dentry name at the base of our mount point */
+ dentry = d_lookup(nd->path.dentry, &nd->last);
+ if (!dentry)
+ goto out;
+
+ dput(nd->path.dentry);
+ nd->path.dentry = dentry;
+
+ /* And follow the mount stack looking for our autofs mount */
+ while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
+ inode = nd->path.dentry->d_inode;
+ if (!inode)
+ break;
+
+ sb = inode->i_sb;
+ s_dev = new_encode_dev(sb->s_dev);
+ if (devno == s_dev) {
+ if (sb->s_magic == AUTOFS_SUPER_MAGIC) {
+ err = 0;
+ break;
+ }
+ }
+ }
+out:
+ return err;
+}
+
+/*
+ * Walk down the mount stack looking for an autofs mount that
+ * has the requested mount type (ie. indirect, direct or offset).
+ */
+static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type)
+{
+ struct dentry *dentry;
+ struct autofs_info *ino;
+ unsigned int err;
+
+ err = -ENOENT;
+
+ /* Lookup the dentry name at the base of our mount point */
+ dentry = d_lookup(nd->path.dentry, &nd->last);
+ if (!dentry)
+ goto out;
+
+ dput(nd->path.dentry);
+ nd->path.dentry = dentry;
+
+ /* And follow the mount stack looking for our autofs mount */
+ while (follow_down(&nd->path.mnt, &nd->path.dentry)) {
+ ino = autofs4_dentry_ino(nd->path.dentry);
+ if (ino && ino->sbi->type & type) {
+ err = 0;
+ break;
+ }
+ }
+out:
+ return err;
+}
+
+static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file)
+{
+ struct files_struct *files = current->files;
+ struct fdtable *fdt;
+
+ spin_lock(&files->file_lock);
+ fdt = files_fdtable(files);
+ BUG_ON(fdt->fd[fd] != NULL);
+ rcu_assign_pointer(fdt->fd[fd], file);
+ FD_SET(fd, fdt->close_on_exec);
+ spin_unlock(&files->file_lock);
+}
+
+
+/*
+ * Open a file descriptor on the autofs mount point corresponding
+ * to the given path and device number (aka. new_encode_dev(sb->s_dev)).
+ */
+static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid)
+{
+ struct file *filp;
+ struct nameidata nd;
+ int err, fd;
+
+ fd = get_unused_fd();
+ if (likely(fd >= 0)) {
+ /* Get nameidata of the parent directory */
+ err = path_lookup(path, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ /*
+ * Search down, within the parent, looking for an
+ * autofs super block that has the device number
+ * corresponding to the autofs fs we want to open.
+ */
+ err = autofs_dev_ioctl_find_super(&nd, devid);
+ if (err) {
+ path_put(&nd.path);
+ goto out;
+ }
+
+ filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY);
+ if (IS_ERR(filp)) {
+ err = PTR_ERR(filp);
+ goto out;
+ }
+
+ autofs_dev_ioctl_fd_install(fd, filp);
+ }
+
+ return fd;
+
+out:
+ put_unused_fd(fd);
+ return err;
+}
+
+/* Open a file descriptor on an autofs mount point */
+static int autofs_dev_ioctl_openmount(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ const char *path;
+ dev_t devid;
+ int err, fd;
+
+ /* param->path has already been checked */
+ if (!param->arg1)
+ return -EINVAL;
+
+ param->ioctlfd = -1;
+
+ path = param->path;
+ devid = param->arg1;
+
+ err = 0;
+ fd = autofs_dev_ioctl_open_mountpoint(path, devid);
+ if (unlikely(fd < 0)) {
+ err = fd;
+ goto out;
+ }
+
+ param->ioctlfd = fd;
+out:
+ return err;
+}
+
+/* Close file descriptor allocated above (user can also use close(2)). */
+static int autofs_dev_ioctl_closemount(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ return sys_close(param->ioctlfd);
+}
+
+/*
+ * Send "ready" status for an existing wait (either a mount or an expire
+ * request).
+ */
+static int autofs_dev_ioctl_ready(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ autofs_wqt_t token;
+
+ token = (autofs_wqt_t) param->arg1;
+ return autofs4_wait_release(sbi, token, 0);
+}
+
+/*
+ * Send "fail" status for an existing wait (either a mount or an expire
+ * request).
+ */
+static int autofs_dev_ioctl_fail(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ autofs_wqt_t token;
+ int status;
+
+ token = (autofs_wqt_t) param->arg1;
+ status = param->arg2 ? param->arg2 : -ENOENT;
+ return autofs4_wait_release(sbi, token, status);
+}
+
+/*
+ * Set the pipe fd for kernel communication to the daemon.
+ *
+ * Normally this is set at mount using an option but if we
+ * are reconnecting to a busy mount then we need to use this
+ * to tell the autofs mount about the new kernel pipe fd. In
+ * order to protect mounts against incorrectly setting the
+ * pipefd we also require that the autofs mount be catatonic.
+ *
+ * This also sets the process group id used to identify the
+ * controlling process (eg. the owning automount(8) daemon).
+ */
+static int autofs_dev_ioctl_setpipefd(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ int pipefd;
+ int err = 0;
+
+ if (param->arg1 == -1)
+ return -EINVAL;
+
+ pipefd = param->arg1;
+
+ mutex_lock(&sbi->wq_mutex);
+ if (!sbi->catatonic) {
+ mutex_unlock(&sbi->wq_mutex);
+ return -EBUSY;
+ } else {
+ struct file *pipe = fget(pipefd);
+ if (!pipe->f_op || !pipe->f_op->write) {
+ err = -EPIPE;
+ fput(pipe);
+ goto out;
+ }
+ sbi->oz_pgrp = task_pgrp_nr(current);
+ sbi->pipefd = pipefd;
+ sbi->pipe = pipe;
+ sbi->catatonic = 0;
+ }
+out:
+ mutex_unlock(&sbi->wq_mutex);
+ return err;
+}
+
+/*
+ * Make the autofs mount point catatonic, no longer responsive to
+ * mount requests. Also closes the kernel pipe file descriptor.
+ */
+static int autofs_dev_ioctl_catatonic(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ autofs4_catatonic_mode(sbi);
+ return 0;
+}
+
+/* Set the autofs mount timeout */
+static int autofs_dev_ioctl_timeout(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ unsigned long timeout;
+
+ timeout = param->arg1;
+ param->arg1 = sbi->exp_timeout / HZ;
+ sbi->exp_timeout = timeout * HZ;
+ return 0;
+}
+
+/*
+ * Return the uid and gid of the last request for the mount
+ *
+ * When reconstructing an autofs mount tree with active mounts
+ * we need to re-connect to mounts that may have used the original
+ * process uid and gid (or string variations of them) for mount
+ * lookups within the map entry.
+ */
+static int autofs_dev_ioctl_requester(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ struct autofs_info *ino;
+ struct nameidata nd;
+ const char *path;
+ dev_t devid;
+ int err = -ENOENT;
+
+ if (param->size <= sizeof(*param)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ path = param->path;
+ devid = sbi->sb->s_dev;
+
+ param->arg1 = param->arg2 = -1;
+
+ /* Get nameidata of the parent directory */
+ err = path_lookup(path, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ err = autofs_dev_ioctl_find_super(&nd, devid);
+ if (err)
+ goto out_release;
+
+ ino = autofs4_dentry_ino(nd.path.dentry);
+ if (ino) {
+ err = 0;
+ autofs4_expire_wait(nd.path.dentry);
+ spin_lock(&sbi->fs_lock);
+ param->arg1 = ino->uid;
+ param->arg2 = ino->gid;
+ spin_unlock(&sbi->fs_lock);
+ }
+
+out_release:
+ path_put(&nd.path);
+out:
+ return err;
+}
+
+/*
+ * Call repeatedly until it returns -EAGAIN, meaning there's nothing
+ * more that can be done.
+ */
+static int autofs_dev_ioctl_expire(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ struct dentry *dentry;
+ struct vfsmount *mnt;
+ int err = -EAGAIN;
+ int how;
+
+ how = param->arg1;
+ mnt = fp->f_path.mnt;
+
+ if (sbi->type & AUTOFS_TYPE_TRIGGER)
+ dentry = autofs4_expire_direct(sbi->sb, mnt, sbi, how);
+ else
+ dentry = autofs4_expire_indirect(sbi->sb, mnt, sbi, how);
+
+ if (dentry) {
+ struct autofs_info *ino = autofs4_dentry_ino(dentry);
+
+ /*
+ * This is synchronous because it makes the daemon a
+ * little easier
+ */
+ err = autofs4_wait(sbi, dentry, NFY_EXPIRE);
+
+ spin_lock(&sbi->fs_lock);
+ if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
+ ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
+ sbi->sb->s_root->d_mounted++;
+ }
+ ino->flags &= ~AUTOFS_INF_EXPIRING;
+ complete_all(&ino->expire_complete);
+ spin_unlock(&sbi->fs_lock);
+ dput(dentry);
+ }
+
+ return err;
+}
+
+/* Check if autofs mount point is in use */
+static int autofs_dev_ioctl_askumount(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ param->arg1 = 0;
+ if (may_umount(fp->f_path.mnt))
+ param->arg1 = 1;
+ return 0;
+}
+
+/*
+ * Check if the given path is a mountpoint.
+ *
+ * If we are supplied with the file descriptor of an autofs
+ * mount we're looking for a specific mount. In this case
+ * the path is considered a mountpoint if it is itself a
+ * mountpoint or contains a mount, such as a multi-mount
+ * without a root mount. In this case we return 1 if the
+ * path is a mount point and the super magic of the covering
+ * mount if there is one or 0 if it isn't a mountpoint.
+ *
+ * If we aren't supplied with a file descriptor then we
+ * lookup the nameidata of the path and check if it is the
+ * root of a mount. If a type is given we are looking for
+ * a particular autofs mount and if we don't find a match
+ * we return fail. If the located nameidata path is the
+ * root of a mount we return 1 along with the super magic
+ * of the mount or 0 otherwise.
+ *
+ * In both cases the the device number (as returned by
+ * new_encode_dev()) is also returned.
+ */
+static int autofs_dev_ioctl_ismountpoint(struct file *fp,
+ struct autofs_sb_info *sbi,
+ struct autofs_dev_ioctl *param)
+{
+ struct nameidata nd;
+ const char *path;
+ unsigned int type;
+ int err = -ENOENT;
+
+ if (param->size <= sizeof(*param)) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ path = param->path;
+ type = param->arg1;
+
+ param->arg1 = 0;
+ param->arg2 = 0;
+
+ if (!fp || param->ioctlfd == -1) {
+ if (type == AUTOFS_TYPE_ANY) {
+ struct super_block *sb;
+
+ err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (err)
+ goto out;
+
+ sb = nd.path.dentry->d_sb;
+ param->arg1 = new_encode_dev(sb->s_dev);
+ } else {
+ struct autofs_info *ino;
+
+ err = path_lookup(path, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ err = autofs_dev_ioctl_find_sbi_type(&nd, type);
+ if (err)
+ goto out_release;
+
+ ino = autofs4_dentry_ino(nd.path.dentry);
+ param->arg1 = autofs4_get_dev(ino->sbi);
+ }
+
+ err = 0;
+ if (nd.path.dentry->d_inode &&
+ nd.path.mnt->mnt_root == nd.path.dentry) {
+ err = 1;
+ param->arg2 = nd.path.dentry->d_inode->i_sb->s_magic;
+ }
+ } else {
+ dev_t devid = new_encode_dev(sbi->sb->s_dev);
+
+ err = path_lookup(path, LOOKUP_PARENT, &nd);
+ if (err)
+ goto out;
+
+ err = autofs_dev_ioctl_find_super(&nd, devid);
+ if (err)
+ goto out_release;
+
+ param->arg1 = autofs4_get_dev(sbi);
+
+ err = have_submounts(nd.path.dentry);
+
+ if (nd.path.mnt->mnt_mountpoint != nd.path.mnt->mnt_root) {
+ if (follow_down(&nd.path.mnt, &nd.path.dentry)) {
+ struct inode *inode = nd.path.dentry->d_inode;
+ param->arg2 = inode->i_sb->s_magic;
+ }
+ }
+ }
+
+out_release:
+ path_put(&nd.path);
+out:
+ return err;
+}
+
+/*
+ * Our range of ioctl numbers isn't 0 based so we need to shift
+ * the array index by _IOC_NR(AUTOFS_CTL_IOC_FIRST) for the table
+ * lookup.
+ */
+#define cmd_idx(cmd) (cmd - _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST))
+
+static ioctl_fn lookup_dev_ioctl(unsigned int cmd)
+{
+ static struct {
+ int cmd;
+ ioctl_fn fn;
+ } _ioctls[] = {
+ {cmd_idx(AUTOFS_DEV_IOCTL_VERSION_CMD), NULL},
+ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOVER_CMD),
+ autofs_dev_ioctl_protover},
+ {cmd_idx(AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD),
+ autofs_dev_ioctl_protosubver},
+ {cmd_idx(AUTOFS_DEV_IOCTL_OPENMOUNT_CMD),
+ autofs_dev_ioctl_openmount},
+ {cmd_idx(AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD),
+ autofs_dev_ioctl_closemount},
+ {cmd_idx(AUTOFS_DEV_IOCTL_READY_CMD),
+ autofs_dev_ioctl_ready},
+ {cmd_idx(AUTOFS_DEV_IOCTL_FAIL_CMD),
+ autofs_dev_ioctl_fail},
+ {cmd_idx(AUTOFS_DEV_IOCTL_SETPIPEFD_CMD),
+ autofs_dev_ioctl_setpipefd},
+ {cmd_idx(AUTOFS_DEV_IOCTL_CATATONIC_CMD),
+ autofs_dev_ioctl_catatonic},
+ {cmd_idx(AUTOFS_DEV_IOCTL_TIMEOUT_CMD),
+ autofs_dev_ioctl_timeout},
+ {cmd_idx(AUTOFS_DEV_IOCTL_REQUESTER_CMD),
+ autofs_dev_ioctl_requester},
+ {cmd_idx(AUTOFS_DEV_IOCTL_EXPIRE_CMD),
+ autofs_dev_ioctl_expire},
+ {cmd_idx(AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD),
+ autofs_dev_ioctl_askumount},
+ {cmd_idx(AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD),
+ autofs_dev_ioctl_ismountpoint}
+ };
+ unsigned int idx = cmd_idx(cmd);
+
+ return (idx >= ARRAY_SIZE(_ioctls)) ? NULL : _ioctls[idx].fn;
+}
+
+/* ioctl dispatcher */
+static int _autofs_dev_ioctl(unsigned int command, struct autofs_dev_ioctl __user *user)
+{
+ struct autofs_dev_ioctl *param;
+ struct file *fp;
+ struct autofs_sb_info *sbi;
+ unsigned int cmd_first, cmd;
+ ioctl_fn fn = NULL;
+ int err = 0;
+
+ /* only root can play with this */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ cmd_first = _IOC_NR(AUTOFS_DEV_IOCTL_IOC_FIRST);
+ cmd = _IOC_NR(command);
+
+ if (_IOC_TYPE(command) != _IOC_TYPE(AUTOFS_DEV_IOCTL_IOC_FIRST) ||
+ cmd - cmd_first >= AUTOFS_DEV_IOCTL_IOC_COUNT) {
+ return -ENOTTY;
+ }
+
+ /* Copy the parameters into kernel space. */
+ param = copy_dev_ioctl(user);
+ if (IS_ERR(param))
+ return PTR_ERR(param);
+
+ err = validate_dev_ioctl(command, param);
+ if (err)
+ goto out;
+
+ /* The validate routine above always sets the version */
+ if (cmd == AUTOFS_DEV_IOCTL_VERSION_CMD)
+ goto done;
+
+ fn = lookup_dev_ioctl(cmd);
+ if (!fn) {
+ AUTOFS_WARN("unknown command 0x%08x", command);
+ return -ENOTTY;
+ }
+
+ fp = NULL;
+ sbi = NULL;
+
+ /*
+ * For obvious reasons the openmount can't have a file
+ * descriptor yet. We don't take a reference to the
+ * file during close to allow for immediate release.
+ */
+ if (cmd != AUTOFS_DEV_IOCTL_OPENMOUNT_CMD &&
+ cmd != AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD) {
+ fp = fget(param->ioctlfd);
+ if (!fp) {
+ if (cmd == AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD)
+ goto cont;
+ err = -EBADF;
+ goto out;
+ }
+
+ if (!fp->f_op) {
+ err = -ENOTTY;
+ fput(fp);
+ goto out;
+ }
+
+ sbi = autofs_dev_ioctl_sbi(fp);
+ if (!sbi || sbi->magic != AUTOFS_SBI_MAGIC) {
+ err = -EINVAL;
+ fput(fp);
+ goto out;
+ }
+
+ /*
+ * Admin needs to be able to set the mount catatonic in
+ * order to be able to perform the re-open.
+ */
+ if (!autofs4_oz_mode(sbi) &&
+ cmd != AUTOFS_DEV_IOCTL_CATATONIC_CMD) {
+ err = -EACCES;
+ fput(fp);
+ goto out;
+ }
+ }
+cont:
+ err = fn(fp, sbi, param);
+
+ if (fp)
+ fput(fp);
+done:
+ if (err >= 0 && copy_to_user(user, param, AUTOFS_DEV_IOCTL_SIZE))
+ err = -EFAULT;
+out:
+ free_dev_ioctl(param);
+ return err;
+}
+
+static long autofs_dev_ioctl(struct file *file, uint command, ulong u)
+{
+ int err;
+ err = _autofs_dev_ioctl(command, (struct autofs_dev_ioctl __user *) u);
+ return (long) err;
+}
+
+#ifdef CONFIG_COMPAT
+static long autofs_dev_ioctl_compat(struct file *file, uint command, ulong u)
+{
+ return (long) autofs_dev_ioctl(file, command, (ulong) compat_ptr(u));
+}
+#else
+#define autofs_dev_ioctl_compat NULL
+#endif
+
+static const struct file_operations _dev_ioctl_fops = {
+ .unlocked_ioctl = autofs_dev_ioctl,
+ .compat_ioctl = autofs_dev_ioctl_compat,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice _autofs_dev_ioctl_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = AUTOFS_DEVICE_NAME,
+ .fops = &_dev_ioctl_fops
+};
+
+/* Register/deregister misc character device */
+int autofs_dev_ioctl_init(void)
+{
+ int r;
+
+ r = misc_register(&_autofs_dev_ioctl_misc);
+ if (r) {
+ AUTOFS_ERROR("misc_register failed for control device");
+ return r;
+ }
+
+ return 0;
+}
+
+void autofs_dev_ioctl_exit(void)
+{
+ misc_deregister(&_autofs_dev_ioctl_misc);
+ return;
+}
+
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index cdabb796ff0..cde2f8e8935 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -244,10 +244,10 @@ cont:
}
/* Check if we can expire a direct mount (possibly a tree) */
-static struct dentry *autofs4_expire_direct(struct super_block *sb,
- struct vfsmount *mnt,
- struct autofs_sb_info *sbi,
- int how)
+struct dentry *autofs4_expire_direct(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi,
+ int how)
{
unsigned long timeout;
struct dentry *root = dget(sb->s_root);
@@ -283,10 +283,10 @@ static struct dentry *autofs4_expire_direct(struct super_block *sb,
* - it is unused by any user process
* - it has been unused for exp_timeout time
*/
-static struct dentry *autofs4_expire_indirect(struct super_block *sb,
- struct vfsmount *mnt,
- struct autofs_sb_info *sbi,
- int how)
+struct dentry *autofs4_expire_indirect(struct super_block *sb,
+ struct vfsmount *mnt,
+ struct autofs_sb_info *sbi,
+ int how)
{
unsigned long timeout;
struct dentry *root = sb->s_root;
@@ -479,7 +479,7 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
if (arg && get_user(do_now, arg))
return -EFAULT;
- if (sbi->type & AUTOFS_TYPE_DIRECT)
+ if (sbi->type & AUTOFS_TYPE_TRIGGER)
dentry = autofs4_expire_direct(sb, mnt, sbi, do_now);
else
dentry = autofs4_expire_indirect(sb, mnt, sbi, do_now);
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index 723a1c5e361..9722e4bd895 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -29,11 +29,20 @@ static struct file_system_type autofs_fs_type = {
static int __init init_autofs4_fs(void)
{
- return register_filesystem(&autofs_fs_type);
+ int err;
+
+ err = register_filesystem(&autofs_fs_type);
+ if (err)
+ return err;
+
+ autofs_dev_ioctl_init();
+
+ return err;
}
static void __exit exit_autofs4_fs(void)
{
+ autofs_dev_ioctl_exit();
unregister_filesystem(&autofs_fs_type);
}
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 45d55819203..c7e65bb30ba 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -53,6 +53,8 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
atomic_set(&ino->count, 0);
}
+ ino->uid = 0;
+ ino->gid = 0;
ino->mode = mode;
ino->last_used = jiffies;
@@ -288,7 +290,7 @@ static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid,
*type = AUTOFS_TYPE_DIRECT;
break;
case Opt_offset:
- *type = AUTOFS_TYPE_DIRECT | AUTOFS_TYPE_OFFSET;
+ *type = AUTOFS_TYPE_OFFSET;
break;
default:
return 1;
@@ -336,7 +338,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->sb = s;
sbi->version = 0;
sbi->sub_version = 0;
- sbi->type = 0;
+ sbi->type = AUTOFS_TYPE_INDIRECT;
sbi->min_proto = 0;
sbi->max_proto = 0;
mutex_init(&sbi->wq_mutex);
@@ -378,7 +380,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
}
root_inode->i_fop = &autofs4_root_operations;
- root_inode->i_op = sbi->type & AUTOFS_TYPE_DIRECT ?
+ root_inode->i_op = sbi->type & AUTOFS_TYPE_TRIGGER ?
&autofs4_direct_root_inode_operations :
&autofs4_indirect_root_inode_operations;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 35216d18d8b..4b67c2a2d77 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -337,7 +337,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
* is very similar for indirect mounts except only dentrys
* in the root of the autofs file system may be negative.
*/
- if (sbi->type & (AUTOFS_TYPE_DIRECT|AUTOFS_TYPE_OFFSET))
+ if (sbi->type & AUTOFS_TYPE_TRIGGER)
return -ENOENT;
else if (!IS_ROOT(dentry->d_parent))
return -ENOENT;
@@ -348,7 +348,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
return -ENOMEM;
/* If this is a direct mount request create a dummy name */
- if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
+ if (IS_ROOT(dentry) && sbi->type & AUTOFS_TYPE_TRIGGER)
qstr.len = sprintf(name, "%p", dentry);
else {
qstr.len = autofs4_getpath(sbi, dentry, &name);
@@ -406,11 +406,11 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
type = autofs_ptype_expire_multi;
} else {
if (notify == NFY_MOUNT)
- type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+ type = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
autofs_ptype_missing_direct :
autofs_ptype_missing_indirect;
else
- type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
+ type = (sbi->type & AUTOFS_TYPE_TRIGGER) ?
autofs_ptype_expire_direct :
autofs_ptype_expire_indirect;
}
@@ -457,6 +457,40 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
status = wq->status;
+ /*
+ * For direct and offset mounts we need to track the requester's
+ * uid and gid in the dentry info struct. This is so it can be
+ * supplied, on request, by the misc device ioctl interface.
+ * This is needed during daemon resatart when reconnecting
+ * to existing, active, autofs mounts. The uid and gid (and
+ * related string values) may be used for macro substitution
+ * in autofs mount maps.
+ */
+ if (!status) {
+ struct autofs_info *ino;
+ struct dentry *de = NULL;
+
+ /* direct mount or browsable map */
+ ino = autofs4_dentry_ino(dentry);
+ if (!ino) {
+ /* If not lookup actual dentry used */
+ de = d_lookup(dentry->d_parent, &dentry->d_name);
+ if (de)
+ ino = autofs4_dentry_ino(de);
+ }
+
+ /* Set mount requester */
+ if (ino) {
+ spin_lock(&sbi->fs_lock);
+ ino->uid = wq->uid;
+ ino->gid = wq->gid;
+ spin_unlock(&sbi->fs_lock);
+ }
+
+ if (de)
+ dput(de);
+ }
+
/* Are we the last process to need status? */
mutex_lock(&sbi->wq_mutex);
if (!--wq->wait_ctr)
diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h
index e2595c2c403..7893eaa1e58 100644
--- a/fs/befs/befs_fs_types.h
+++ b/fs/befs/befs_fs_types.h
@@ -55,8 +55,12 @@ enum super_flags {
};
#define BEFS_BYTEORDER_NATIVE 0x42494745
+#define BEFS_BYTEORDER_NATIVE_LE (__force fs32)cpu_to_le32(BEFS_BYTEORDER_NATIVE)
+#define BEFS_BYTEORDER_NATIVE_BE (__force fs32)cpu_to_be32(BEFS_BYTEORDER_NATIVE)
#define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1
+#define BEFS_SUPER_MAGIC1_LE (__force fs32)cpu_to_le32(BEFS_SUPER_MAGIC1)
+#define BEFS_SUPER_MAGIC1_BE (__force fs32)cpu_to_be32(BEFS_SUPER_MAGIC1)
/*
* Flags of inode
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 9286b2af893..b6dfee37c7b 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -809,8 +809,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
/* account for offset of super block on x86 */
disk_sb = (befs_super_block *) bh->b_data;
- if ((le32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1) ||
- (be32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1)) {
+ if ((disk_sb->magic1 == BEFS_SUPER_MAGIC1_LE) ||
+ (disk_sb->magic1 == BEFS_SUPER_MAGIC1_BE)) {
befs_debug(sb, "Using PPC superblock location");
} else {
befs_debug(sb, "Using x86 superblock location");
diff --git a/fs/befs/super.c b/fs/befs/super.c
index 8c3401ff6d6..41f2b4d0093 100644
--- a/fs/befs/super.c
+++ b/fs/befs/super.c
@@ -26,10 +26,10 @@ befs_load_sb(struct super_block *sb, befs_super_block * disk_sb)
befs_sb_info *befs_sb = BEFS_SB(sb);
/* Check the byte order of the filesystem */
- if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
+ if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_LE)
befs_sb->byte_order = BEFS_BYTESEX_LE;
- else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE)
- befs_sb->byte_order = BEFS_BYTESEX_BE;
+ else if (disk_sb->fs_byte_order == BEFS_BYTEORDER_NATIVE_BE)
+ befs_sb->byte_order = BEFS_BYTESEX_BE;
befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1);
befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 80c1f952ef7..0e8367c5462 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -25,6 +25,7 @@
#include <linux/fcntl.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
+#include <linux/security.h>
#include <linux/highmem.h>
#include <linux/highuid.h>
#include <linux/personality.h>
@@ -455,8 +456,19 @@ error_kill:
}
/*****************************************************************************/
+
+#ifndef ELF_BASE_PLATFORM
/*
- * present useful information to the program
+ * AT_BASE_PLATFORM indicates the "real" hardware/microarchitecture.
+ * If the arch defines ELF_BASE_PLATFORM (in asm/elf.h), the value
+ * will be copied to the user stack in the same manner as AT_PLATFORM.
+ */
+#define ELF_BASE_PLATFORM NULL
+#endif
+
+/*
+ * present useful information to the program by shovelling it onto the new
+ * process's stack
*/
static int create_elf_fdpic_tables(struct linux_binprm *bprm,
struct mm_struct *mm,
@@ -466,15 +478,19 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
unsigned long sp, csp, nitems;
elf_caddr_t __user *argv, *envp;
size_t platform_len = 0, len;
- char *k_platform;
- char __user *u_platform, *p;
+ char *k_platform, *k_base_platform;
+ char __user *u_platform, *u_base_platform, *p;
long hwcap;
int loop;
int nr; /* reset for each csp adjustment */
- /* we're going to shovel a whole load of stuff onto the stack */
#ifdef CONFIG_MMU
- sp = bprm->p;
+ /* 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 is
+ * to shuffle the initial stack for them, so we give the architecture
+ * an opportunity to do so here.
+ */
+ sp = arch_align_stack(bprm->p);
#else
sp = mm->start_stack;
@@ -483,11 +499,14 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
return -EFAULT;
#endif
- /* get hold of platform and hardware capabilities masks for the machine
- * we are running on. In some cases (Sparc), this info is impossible
- * to get, in others (i386) it is merely difficult.
- */
hwcap = ELF_HWCAP;
+
+ /*
+ * If this architecture has a platform capability string, copy it
+ * to userspace. In some cases (Sparc), this info is impossible
+ * for userspace to get any other way, in others (i386) it is
+ * merely difficult.
+ */
k_platform = ELF_PLATFORM;
u_platform = NULL;
@@ -499,19 +518,20 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
return -EFAULT;
}
-#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 is
- * to shuffle the initial stack for them.
- *
- * the conditionals here are unneeded, but kept in to make the code
- * behaviour the same as pre change unless we have hyperthreaded
- * processors. This keeps Mr Marcelo Person happier but should be
- * removed for 2.5
+ /*
+ * If this architecture has a "base" platform capability
+ * string, copy it to userspace.
*/
- if (smp_num_siblings > 1)
- sp = sp - ((current->pid % 64) << 7);
-#endif
+ k_base_platform = ELF_BASE_PLATFORM;
+ u_base_platform = NULL;
+
+ if (k_base_platform) {
+ platform_len = strlen(k_base_platform) + 1;
+ sp -= platform_len;
+ u_base_platform = (char __user *) sp;
+ if (__copy_to_user(u_base_platform, k_base_platform, platform_len) != 0)
+ return -EFAULT;
+ }
sp &= ~7UL;
@@ -541,9 +561,13 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
}
/* force 16 byte _final_ alignment here for generality */
-#define DLINFO_ITEMS 13
+#define DLINFO_ITEMS 15
+
+ nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) +
+ (k_base_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH;
- nitems = 1 + DLINFO_ITEMS + (k_platform ? 1 : 0) + AT_VECTOR_SIZE_ARCH;
+ if (bprm->interp_flags & BINPRM_FLAGS_EXECFD)
+ nitems++;
csp = sp;
sp -= nitems * 2 * sizeof(unsigned long);
@@ -575,6 +599,19 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
(elf_addr_t) (unsigned long) u_platform);
}
+ if (k_base_platform) {
+ nr = 0;
+ csp -= 2 * sizeof(unsigned long);
+ NEW_AUX_ENT(AT_BASE_PLATFORM,
+ (elf_addr_t) (unsigned long) u_base_platform);
+ }
+
+ if (bprm->interp_flags & BINPRM_FLAGS_EXECFD) {
+ nr = 0;
+ csp -= 2 * sizeof(unsigned long);
+ NEW_AUX_ENT(AT_EXECFD, bprm->interp_data);
+ }
+
nr = 0;
csp -= DLINFO_ITEMS * 2 * sizeof(unsigned long);
NEW_AUX_ENT(AT_HWCAP, hwcap);
@@ -590,6 +627,8 @@ static int create_elf_fdpic_tables(struct linux_binprm *bprm,
NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid);
NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid);
NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid);
+ NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));
+ NEW_AUX_ENT(AT_EXECFN, bprm->exec);
#ifdef ARCH_DLINFO
nr = 0;
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index f9c88d0c8ce..32fb00b52cd 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -43,7 +43,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
return -ENOEXEC;
}
- bprm->sh_bang = 1; /* Well, the bang-shell is implicit... */
+ bprm->recursion_depth++; /* Well, the bang-shell is implicit... */
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index dfc0197905c..ccb781a6a80 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -229,13 +229,13 @@ static int decompress_exec(
ret = 10;
if (buf[3] & EXTRA_FIELD) {
ret += 2 + buf[10] + (buf[11] << 8);
- if (unlikely(LBUFSIZE == ret)) {
+ if (unlikely(LBUFSIZE <= ret)) {
DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
goto out_free_buf;
}
}
if (buf[3] & ORIG_NAME) {
- for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
+ while (ret < LBUFSIZE && buf[ret++] != 0)
;
if (unlikely(LBUFSIZE == ret)) {
DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
@@ -243,7 +243,7 @@ static int decompress_exec(
}
}
if (buf[3] & COMMENT) {
- for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
+ while (ret < LBUFSIZE && buf[ret++] != 0)
;
if (unlikely(LBUFSIZE == ret)) {
DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 8d7e88e02e0..f2744ab4e5b 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -117,7 +117,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
goto _ret;
retval = -ENOEXEC;
- if (bprm->misc_bang)
+ if (bprm->recursion_depth > BINPRM_MAX_RECURSION)
goto _ret;
/* to keep locking time low, we copy the interpreter string */
@@ -197,7 +197,7 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (retval < 0)
goto _error;
- bprm->misc_bang = 1;
+ bprm->recursion_depth++;
retval = search_binary_handler (bprm, regs);
if (retval < 0)
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index 9e3963f7ebf..08343505e18 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -22,14 +22,15 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
char interp[BINPRM_BUF_SIZE];
int retval;
- if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') || (bprm->sh_bang))
+ if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!') ||
+ (bprm->recursion_depth > BINPRM_MAX_RECURSION))
return -ENOEXEC;
/*
* This section does the #! interpretation.
* Sorta complicated, but hopefully it will work. -TYT
*/
- bprm->sh_bang = 1;
+ bprm->recursion_depth++;
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 68be580ba28..74e587a5279 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -306,3 +306,5 @@ static void __exit exit_som_binfmt(void)
core_initcall(init_som_binfmt);
module_exit(exit_som_binfmt);
+
+MODULE_LICENSE("GPL");
diff --git a/fs/compat.c b/fs/compat.c
index 075d0509970..5f9ec449c79 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -137,6 +137,45 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _
return compat_sys_futimesat(AT_FDCWD, filename, t);
}
+static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
+{
+ compat_ino_t ino = stat->ino;
+ typeof(ubuf->st_uid) uid = 0;
+ typeof(ubuf->st_gid) gid = 0;
+ int err;
+
+ SET_UID(uid, stat->uid);
+ SET_GID(gid, stat->gid);
+
+ if ((u64) stat->size > MAX_NON_LFS ||
+ !old_valid_dev(stat->dev) ||
+ !old_valid_dev(stat->rdev))
+ return -EOVERFLOW;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
+ if (clear_user(ubuf, sizeof(*ubuf)))
+ return -EFAULT;
+
+ err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
+ err |= __put_user(ino, &ubuf->st_ino);
+ err |= __put_user(stat->mode, &ubuf->st_mode);
+ err |= __put_user(stat->nlink, &ubuf->st_nlink);
+ err |= __put_user(uid, &ubuf->st_uid);
+ err |= __put_user(gid, &ubuf->st_gid);
+ err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
+ err |= __put_user(stat->size, &ubuf->st_size);
+ err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
+ err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
+ err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
+ err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
+ err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
+ err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
+ err |= __put_user(stat->blksize, &ubuf->st_blksize);
+ err |= __put_user(stat->blocks, &ubuf->st_blocks);
+ return err;
+}
+
asmlinkage long compat_sys_newstat(char __user * filename,
struct compat_stat __user *statbuf)
{
@@ -1239,7 +1278,7 @@ static int compat_count(compat_uptr_t __user *argv, int max)
if (!p)
break;
argv++;
- if(++i > max)
+ if (i++ >= max)
return -E2BIG;
}
}
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 9606ee848fd..af0558dbe8b 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -5,11 +5,11 @@
*
* O_DIRECT
*
- * 04Jul2002 akpm@zip.com.au
+ * 04Jul2002 Andrew Morton
* Initial version
* 11Sep2002 janetinc@us.ibm.com
* added readv/writev support.
- * 29Oct2002 akpm@zip.com.au
+ * 29Oct2002 Andrew Morton
* rewrote bio_add_page() support.
* 30Oct2002 pbadari@us.ibm.com
* added support for non-aligned IO.
diff --git a/fs/dquot.c b/fs/dquot.c
index ad7e59003e0..da30a27f224 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -9,8 +9,6 @@
* implementation is based on one of the several variants of the LINUX
* inode-subsystem with added complexity of the diskquota system.
*
- * Version: $Id: dquot.c,v 6.3 1996/11/17 18:35:34 mvw Exp mvw $
- *
* Author: Marco van Wieringen <mvw@planets.elm.net>
*
* Fixes: Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index b4755a85996..2cc9ee4ad2e 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o miscdev.o kthread.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o miscdev.o kthread.o debug.o
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index b73fb752c5f..3504cf9df35 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -79,11 +79,6 @@
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
#define ECRYPTFS_DEFAULT_NUM_USERS 4
#define ECRYPTFS_MAX_NUM_USERS 32768
-#define ECRYPTFS_TRANSPORT_NETLINK 0
-#define ECRYPTFS_TRANSPORT_CONNECTOR 1
-#define ECRYPTFS_TRANSPORT_RELAYFS 2
-#define ECRYPTFS_TRANSPORT_MISCDEV 3
-#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_MISCDEV
#define ECRYPTFS_XATTR_NAME "user.ecryptfs"
#define RFC2440_CIPHER_DES3_EDE 0x02
@@ -400,8 +395,6 @@ struct ecryptfs_msg_ctx {
struct mutex mux;
};
-extern unsigned int ecryptfs_transport;
-
struct ecryptfs_daemon;
struct ecryptfs_daemon {
@@ -627,31 +620,20 @@ int
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
-int ecryptfs_process_helo(unsigned int transport, uid_t euid,
- struct user_namespace *user_ns, struct pid *pid);
+int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid);
int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
struct pid *pid);
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
struct user_namespace *user_ns, struct pid *pid,
u32 seq);
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+int ecryptfs_send_message(char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx);
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **emsg);
-int ecryptfs_init_messaging(unsigned int transport);
-void ecryptfs_release_messaging(unsigned int transport);
+int ecryptfs_init_messaging(void);
+void ecryptfs_release_messaging(void);
-int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
- u16 msg_flags, struct pid *daemon_pid);
-int ecryptfs_init_netlink(void);
-void ecryptfs_release_netlink(void);
-
-int ecryptfs_send_connector(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
- u16 msg_flags, struct pid *daemon_pid);
-int ecryptfs_init_connector(void);
-void ecryptfs_release_connector(void);
void
ecryptfs_write_header_metadata(char *virt,
struct ecryptfs_crypt_stat *crypt_stat,
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 9244d653743..eb3dc4c7ac0 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -71,12 +71,11 @@ struct ecryptfs_getdents_callback {
void *dirent;
struct dentry *dentry;
filldir_t filldir;
- int err;
int filldir_called;
int entries_written;
};
-/* Inspired by generic filldir in fs/readir.c */
+/* Inspired by generic filldir in fs/readdir.c */
static int
ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
u64 ino, unsigned int d_type)
@@ -125,18 +124,18 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
buf.dirent = dirent;
buf.dentry = file->f_path.dentry;
buf.filldir = filldir;
-retry:
buf.filldir_called = 0;
buf.entries_written = 0;
- buf.err = 0;
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
- if (buf.err)
- rc = buf.err;
- if (buf.filldir_called && !buf.entries_written)
- goto retry;
file->f_pos = lower_file->f_pos;
+ if (rc < 0)
+ goto out;
+ if (buf.filldir_called && !buf.entries_written)
+ goto out;
if (rc >= 0)
- fsstack_copy_attr_atime(inode, lower_file->f_path.dentry->d_inode);
+ fsstack_copy_attr_atime(inode,
+ lower_file->f_path.dentry->d_inode);
+out:
return rc;
}
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index f5b76a331b9..e22bc396134 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -234,8 +234,8 @@ parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
}
i += data_len;
if (message_len < (i + m_size)) {
- ecryptfs_printk(KERN_ERR, "The received netlink message is "
- "shorter than expected\n");
+ ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd "
+ "is shorter than expected\n");
rc = -EIO;
goto out;
}
@@ -438,8 +438,8 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_msg_ctx *msg_ctx;
struct ecryptfs_message *msg = NULL;
char *auth_tok_sig;
- char *netlink_message;
- size_t netlink_message_length;
+ char *payload;
+ size_t payload_len;
int rc;
rc = ecryptfs_get_auth_tok_sig(&auth_tok_sig, auth_tok);
@@ -449,15 +449,15 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
goto out;
}
rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
- &netlink_message, &netlink_message_length);
+ &payload, &payload_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
goto out;
}
- rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,
- netlink_message_length, &msg_ctx);
+ rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error sending netlink message\n");
+ ecryptfs_printk(KERN_ERR, "Error sending message to "
+ "ecryptfsd\n");
goto out;
}
rc = ecryptfs_wait_for_response(msg_ctx, &msg);
@@ -1333,23 +1333,22 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
struct ecryptfs_key_record *key_rec)
{
struct ecryptfs_msg_ctx *msg_ctx = NULL;
- char *netlink_payload;
- size_t netlink_payload_length;
+ char *payload = NULL;
+ size_t payload_len;
struct ecryptfs_message *msg;
int rc;
rc = write_tag_66_packet(auth_tok->token.private_key.signature,
ecryptfs_code_for_cipher_string(crypt_stat),
- crypt_stat, &netlink_payload,
- &netlink_payload_length);
+ crypt_stat, &payload, &payload_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n");
goto out;
}
- rc = ecryptfs_send_message(ecryptfs_transport, netlink_payload,
- netlink_payload_length, &msg_ctx);
+ rc = ecryptfs_send_message(payload, payload_len, &msg_ctx);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Error sending netlink message\n");
+ ecryptfs_printk(KERN_ERR, "Error sending message to "
+ "ecryptfsd\n");
goto out;
}
rc = ecryptfs_wait_for_response(msg_ctx, &msg);
@@ -1364,8 +1363,7 @@ pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
ecryptfs_printk(KERN_ERR, "Error parsing tag 67 packet\n");
kfree(msg);
out:
- if (netlink_payload)
- kfree(netlink_payload);
+ kfree(payload);
return rc;
}
/**
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 8ebe9a5d1d9..046e027a4cb 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -30,7 +30,6 @@
#include <linux/namei.h>
#include <linux/skbuff.h>
#include <linux/crypto.h>
-#include <linux/netlink.h>
#include <linux/mount.h>
#include <linux/pagemap.h>
#include <linux/key.h>
@@ -49,8 +48,7 @@ MODULE_PARM_DESC(ecryptfs_verbosity,
"0, which is Quiet)");
/**
- * Module parameter that defines the number of netlink message buffer
- * elements
+ * Module parameter that defines the number of message buffer elements
*/
unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS;
@@ -60,9 +58,9 @@ MODULE_PARM_DESC(ecryptfs_message_buf_len,
/**
* Module parameter that defines the maximum guaranteed amount of time to wait
- * for a response through netlink. The actual sleep time will be, more than
+ * for a response from ecryptfsd. The actual sleep time will be, more than
* likely, a small amount greater than this specified value, but only less if
- * the netlink message successfully arrives.
+ * the message successfully arrives.
*/
signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ;
@@ -83,8 +81,6 @@ module_param(ecryptfs_number_of_users, uint, 0);
MODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of "
"concurrent users of eCryptfs");
-unsigned int ecryptfs_transport = ECRYPTFS_DEFAULT_TRANSPORT;
-
void __ecryptfs_printk(const char *fmt, ...)
{
va_list args;
@@ -779,10 +775,11 @@ static int __init ecryptfs_init(void)
"rc = [%d]\n", __func__, rc);
goto out_do_sysfs_unregistration;
}
- rc = ecryptfs_init_messaging(ecryptfs_transport);
+ rc = ecryptfs_init_messaging();
if (rc) {
printk(KERN_ERR "Failure occured while attempting to "
- "initialize the eCryptfs netlink socket\n");
+ "initialize the communications channel to "
+ "ecryptfsd\n");
goto out_destroy_kthread;
}
rc = ecryptfs_init_crypto();
@@ -797,7 +794,7 @@ static int __init ecryptfs_init(void)
goto out;
out_release_messaging:
- ecryptfs_release_messaging(ecryptfs_transport);
+ ecryptfs_release_messaging();
out_destroy_kthread:
ecryptfs_destroy_kthread();
out_do_sysfs_unregistration:
@@ -818,7 +815,7 @@ static void __exit ecryptfs_exit(void)
if (rc)
printk(KERN_ERR "Failure whilst attempting to destroy crypto; "
"rc = [%d]\n", rc);
- ecryptfs_release_messaging(ecryptfs_transport);
+ ecryptfs_release_messaging();
ecryptfs_destroy_kthread();
do_sysfs_unregistration();
unregister_filesystem(&ecryptfs_fs_type);
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index 1b5c20058ac..c6983978a31 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -134,12 +134,11 @@ out:
}
static int
-ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
- u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
+ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
+ struct ecryptfs_msg_ctx **msg_ctx);
/**
* ecryptfs_send_raw_message
- * @transport: Transport type
* @msg_type: Message type
* @daemon: Daemon struct for recipient of message
*
@@ -150,38 +149,25 @@ ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
*
* Returns zero on success; non-zero otherwise
*/
-static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
+static int ecryptfs_send_raw_message(u8 msg_type,
struct ecryptfs_daemon *daemon)
{
struct ecryptfs_msg_ctx *msg_ctx;
int rc;
- switch(transport) {
- case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
- daemon->pid);
- break;
- case ECRYPTFS_TRANSPORT_MISCDEV:
- rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
- &msg_ctx);
- if (rc) {
- printk(KERN_ERR "%s: Error whilst attempting to send "
- "message via procfs; rc = [%d]\n", __func__, rc);
- goto out;
- }
- /* Raw messages are logically context-free (e.g., no
- * reply is expected), so we set the state of the
- * ecryptfs_msg_ctx object to indicate that it should
- * be freed as soon as the transport sends out the message. */
- mutex_lock(&msg_ctx->mux);
- msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
- mutex_unlock(&msg_ctx->mux);
- break;
- case ECRYPTFS_TRANSPORT_CONNECTOR:
- case ECRYPTFS_TRANSPORT_RELAYFS:
- default:
- rc = -ENOSYS;
+ rc = ecryptfs_send_message_locked(NULL, 0, msg_type, &msg_ctx);
+ if (rc) {
+ printk(KERN_ERR "%s: Error whilst attempting to send "
+ "message to ecryptfsd; rc = [%d]\n", __func__, rc);
+ goto out;
}
+ /* Raw messages are logically context-free (e.g., no
+ * reply is expected), so we set the state of the
+ * ecryptfs_msg_ctx object to indicate that it should
+ * be freed as soon as the message is sent. */
+ mutex_lock(&msg_ctx->mux);
+ msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
+ mutex_unlock(&msg_ctx->mux);
out:
return rc;
}
@@ -227,7 +213,6 @@ out:
/**
* ecryptfs_process_helo
- * @transport: The underlying transport (netlink, etc.)
* @euid: The user ID owner of the message
* @user_ns: The namespace in which @euid applies
* @pid: The process ID for the userspace program that sent the
@@ -239,8 +224,8 @@ out:
* Returns zero after adding a new daemon to the hash list;
* non-zero otherwise.
*/
-int ecryptfs_process_helo(unsigned int transport, uid_t euid,
- struct user_namespace *user_ns, struct pid *pid)
+int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
{
struct ecryptfs_daemon *new_daemon;
struct ecryptfs_daemon *old_daemon;
@@ -252,8 +237,7 @@ int ecryptfs_process_helo(unsigned int transport, uid_t euid,
printk(KERN_WARNING "Received request from user [%d] "
"to register daemon [0x%p]; unregistering daemon "
"[0x%p]\n", euid, pid, old_daemon->pid);
- rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
- old_daemon);
+ rc = ecryptfs_send_raw_message(ECRYPTFS_MSG_QUIT, old_daemon);
if (rc)
printk(KERN_WARNING "Failed to send QUIT "
"message to daemon [0x%p]; rc = [%d]\n",
@@ -467,8 +451,6 @@ out:
/**
* ecryptfs_send_message_locked
- * @transport: The transport over which to send the message (i.e.,
- * netlink)
* @data: The data to send
* @data_len: The length of data
* @msg_ctx: The message context allocated for the send
@@ -478,8 +460,8 @@ out:
* Returns zero on success; non-zero otherwise
*/
static int
-ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
- u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
+ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,
+ struct ecryptfs_msg_ctx **msg_ctx)
{
struct ecryptfs_daemon *daemon;
int rc;
@@ -503,20 +485,8 @@ ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
mutex_unlock(&(*msg_ctx)->mux);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
- switch (transport) {
- case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
- 0, daemon->pid);
- break;
- case ECRYPTFS_TRANSPORT_MISCDEV:
- rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
- 0, daemon);
- break;
- case ECRYPTFS_TRANSPORT_CONNECTOR:
- case ECRYPTFS_TRANSPORT_RELAYFS:
- default:
- rc = -ENOSYS;
- }
+ rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,
+ daemon);
if (rc)
printk(KERN_ERR "%s: Error attempting to send message to "
"userspace daemon; rc = [%d]\n", __func__, rc);
@@ -526,8 +496,6 @@ out:
/**
* ecryptfs_send_message
- * @transport: The transport over which to send the message (i.e.,
- * netlink)
* @data: The data to send
* @data_len: The length of data
* @msg_ctx: The message context allocated for the send
@@ -536,14 +504,14 @@ out:
*
* Returns zero on success; non-zero otherwise
*/
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+int ecryptfs_send_message(char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx)
{
int rc;
mutex_lock(&ecryptfs_daemon_hash_mux);
- rc = ecryptfs_send_message_locked(transport, data, data_len,
- ECRYPTFS_MSG_REQUEST, msg_ctx);
+ rc = ecryptfs_send_message_locked(data, data_len, ECRYPTFS_MSG_REQUEST,
+ msg_ctx);
mutex_unlock(&ecryptfs_daemon_hash_mux);
return rc;
}
@@ -586,7 +554,7 @@ sleep:
return rc;
}
-int ecryptfs_init_messaging(unsigned int transport)
+int ecryptfs_init_messaging(void)
{
int i;
int rc = 0;
@@ -639,27 +607,14 @@ int ecryptfs_init_messaging(unsigned int transport)
mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux);
}
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
- switch(transport) {
- case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_init_netlink();
- if (rc)
- ecryptfs_release_messaging(transport);
- break;
- case ECRYPTFS_TRANSPORT_MISCDEV:
- rc = ecryptfs_init_ecryptfs_miscdev();
- if (rc)
- ecryptfs_release_messaging(transport);
- break;
- case ECRYPTFS_TRANSPORT_CONNECTOR:
- case ECRYPTFS_TRANSPORT_RELAYFS:
- default:
- rc = -ENOSYS;
- }
+ rc = ecryptfs_init_ecryptfs_miscdev();
+ if (rc)
+ ecryptfs_release_messaging();
out:
return rc;
}
-void ecryptfs_release_messaging(unsigned int transport)
+void ecryptfs_release_messaging(void)
{
if (ecryptfs_msg_ctx_arr) {
int i;
@@ -698,17 +653,6 @@ void ecryptfs_release_messaging(unsigned int transport)
kfree(ecryptfs_daemon_hash);
mutex_unlock(&ecryptfs_daemon_hash_mux);
}
- switch(transport) {
- case ECRYPTFS_TRANSPORT_NETLINK:
- ecryptfs_release_netlink();
- break;
- case ECRYPTFS_TRANSPORT_MISCDEV:
- ecryptfs_destroy_ecryptfs_miscdev();
- break;
- case ECRYPTFS_TRANSPORT_CONNECTOR:
- case ECRYPTFS_TRANSPORT_RELAYFS:
- default:
- break;
- }
+ ecryptfs_destroy_ecryptfs_miscdev();
return;
}
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 245c2dc02d5..04d7b3fa1ac 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -265,22 +265,34 @@ out:
}
/**
- * ecryptfs_prepare_write
+ * ecryptfs_write_begin
* @file: The eCryptfs file
- * @page: The eCryptfs page
- * @from: The start byte from which we will write
- * @to: The end byte to which we will write
+ * @mapping: The eCryptfs object
+ * @pos: The file offset at which to start writing
+ * @len: Length of the write
+ * @flags: Various flags
+ * @pagep: Pointer to return the page
+ * @fsdata: Pointer to return fs data (unused)
*
* This function must zero any hole we create
*
* Returns zero on success; non-zero otherwise
*/
-static int ecryptfs_prepare_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
+static int ecryptfs_write_begin(struct file *file,
+ struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned flags,
+ struct page **pagep, void **fsdata)
{
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ struct page *page;
loff_t prev_page_end_size;
int rc = 0;
+ page = __grab_cache_page(mapping, index);
+ if (!page)
+ return -ENOMEM;
+ *pagep = page;
+
if (!PageUptodate(page)) {
struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(
@@ -289,8 +301,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)
|| (crypt_stat->flags & ECRYPTFS_NEW_FILE)) {
rc = ecryptfs_read_lower_page_segment(
- page, page->index, 0, PAGE_CACHE_SIZE,
- page->mapping->host);
+ page, index, 0, PAGE_CACHE_SIZE, mapping->host);
if (rc) {
printk(KERN_ERR "%s: Error attemping to read "
"lower page segment; rc = [%d]\n",
@@ -316,8 +327,8 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
SetPageUptodate(page);
} else {
rc = ecryptfs_read_lower_page_segment(
- page, page->index, 0, PAGE_CACHE_SIZE,
- page->mapping->host);
+ page, index, 0, PAGE_CACHE_SIZE,
+ mapping->host);
if (rc) {
printk(KERN_ERR "%s: Error reading "
"page; rc = [%d]\n",
@@ -339,10 +350,10 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
SetPageUptodate(page);
}
}
- prev_page_end_size = ((loff_t)page->index << PAGE_CACHE_SHIFT);
+ prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT);
/* If creating a page or more of holes, zero them out via truncate.
* Note, this will increase i_size. */
- if (page->index != 0) {
+ if (index != 0) {
if (prev_page_end_size > i_size_read(page->mapping->host)) {
rc = ecryptfs_truncate(file->f_path.dentry,
prev_page_end_size);
@@ -357,8 +368,8 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
}
/* Writing to a new page, and creating a small hole from start
* of page? Zero it out. */
- if ((i_size_read(page->mapping->host) == prev_page_end_size)
- && (from != 0))
+ if ((i_size_read(mapping->host) == prev_page_end_size)
+ && (pos != 0))
zero_user(page, 0, PAGE_CACHE_SIZE);
out:
return rc;
@@ -445,21 +456,28 @@ int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)
}
/**
- * ecryptfs_commit_write
+ * ecryptfs_write_end
* @file: The eCryptfs file object
+ * @mapping: The eCryptfs object
+ * @pos: The file position
+ * @len: The length of the data (unused)
+ * @copied: The amount of data copied
* @page: The eCryptfs page
- * @from: Ignored (we rotate the page IV on each write)
- * @to: Ignored
+ * @fsdata: The fsdata (unused)
*
* This is where we encrypt the data and pass the encrypted data to
* the lower filesystem. In OpenPGP-compatible mode, we operate on
* entire underlying packets.
*/
-static int ecryptfs_commit_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
+static int ecryptfs_write_end(struct file *file,
+ struct address_space *mapping,
+ loff_t pos, unsigned len, unsigned copied,
+ struct page *page, void *fsdata)
{
- loff_t pos;
- struct inode *ecryptfs_inode = page->mapping->host;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ unsigned from = pos & (PAGE_CACHE_SIZE - 1);
+ unsigned to = from + copied;
+ struct inode *ecryptfs_inode = mapping->host;
struct ecryptfs_crypt_stat *crypt_stat =
&ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;
int rc;
@@ -471,25 +489,22 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
} else
ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
- "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
- to);
+ "(page w/ index = [0x%.16x], to = [%d])\n", index, to);
/* Fills in zeros if 'to' goes beyond inode size */
rc = fill_zeros_to_end_of_page(page, to);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
- "zeros in page with index = [0x%.16x]\n",
- page->index);
+ "zeros in page with index = [0x%.16x]\n", index);
goto out;
}
rc = ecryptfs_encrypt_page(page);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
- "index [0x%.16x])\n", page->index);
+ "index [0x%.16x])\n", index);
goto out;
}
- pos = (((loff_t)page->index) << PAGE_CACHE_SHIFT) + to;
- if (pos > i_size_read(ecryptfs_inode)) {
- i_size_write(ecryptfs_inode, pos);
+ if (pos + copied > i_size_read(ecryptfs_inode)) {
+ i_size_write(ecryptfs_inode, pos + copied);
ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
"[0x%.16x]\n", i_size_read(ecryptfs_inode));
}
@@ -497,7 +512,11 @@ static int ecryptfs_commit_write(struct file *file, struct page *page,
if (rc)
printk(KERN_ERR "Error writing inode size to metadata; "
"rc = [%d]\n", rc);
+ else
+ rc = copied;
out:
+ unlock_page(page);
+ page_cache_release(page);
return rc;
}
@@ -518,7 +537,7 @@ static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
struct address_space_operations ecryptfs_aops = {
.writepage = ecryptfs_writepage,
.readpage = ecryptfs_readpage,
- .prepare_write = ecryptfs_prepare_write,
- .commit_write = ecryptfs_commit_write,
+ .write_begin = ecryptfs_write_begin,
+ .write_end = ecryptfs_write_end,
.bmap = ecryptfs_bmap,
};
diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c
deleted file mode 100644
index e0abad62b39..00000000000
--- a/fs/ecryptfs/netlink.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
- * eCryptfs: Linux filesystem encryption layer
- *
- * Copyright (C) 2004-2006 International Business Machines Corp.
- * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
- * Tyler Hicks <tyhicks@ou.edu>
- *
- * 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 <net/sock.h>
-#include <linux/hash.h>
-#include <linux/random.h>
-#include "ecryptfs_kernel.h"
-
-static struct sock *ecryptfs_nl_sock;
-
-/**
- * ecryptfs_send_netlink
- * @data: The data to include as the payload
- * @data_len: The byte count of the data
- * @msg_ctx: The netlink context that will be used to handle the
- * response message
- * @msg_type: The type of netlink message to send
- * @msg_flags: The flags to include in the netlink header
- * @daemon_pid: The process id of the daemon to send the message to
- *
- * Sends the data to the specified daemon pid and uses the netlink
- * context element to store the data needed for validation upon
- * receiving the response. The data and the netlink context can be
- * null if just sending a netlink header is sufficient. Returns zero
- * upon sending the message; non-zero upon error.
- */
-int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
- u16 msg_flags, struct pid *daemon_pid)
-{
- struct sk_buff *skb;
- struct nlmsghdr *nlh;
- struct ecryptfs_message *msg;
- size_t payload_len;
- int rc;
-
- payload_len = ((data && data_len) ? (sizeof(*msg) + data_len) : 0);
- skb = alloc_skb(NLMSG_SPACE(payload_len), GFP_KERNEL);
- if (!skb) {
- rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n");
- goto out;
- }
- nlh = NLMSG_PUT(skb, pid_nr(daemon_pid), msg_ctx ? msg_ctx->counter : 0,
- msg_type, payload_len);
- nlh->nlmsg_flags = msg_flags;
- if (msg_ctx && payload_len) {
- msg = (struct ecryptfs_message *)NLMSG_DATA(nlh);
- msg->index = msg_ctx->index;
- msg->data_len = data_len;
- memcpy(msg->data, data, data_len);
- }
- rc = netlink_unicast(ecryptfs_nl_sock, skb, pid_nr(daemon_pid), 0);
- if (rc < 0) {
- ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink "
- "message; rc = [%d]\n", rc);
- goto out;
- }
- rc = 0;
- goto out;
-nlmsg_failure:
- rc = -EMSGSIZE;
- kfree_skb(skb);
-out:
- return rc;
-}
-
-/**
- * ecryptfs_process_nl_reponse
- * @skb: The socket buffer containing the netlink message of state
- * RESPONSE
- *
- * Processes a response message after sending a operation request to
- * userspace. Attempts to assign the msg to a netlink context element
- * at the index specified in the msg. The sk_buff and nlmsghdr must
- * be validated before this function. Returns zero upon delivery to
- * desired context element; non-zero upon delivery failure or error.
- */
-static int ecryptfs_process_nl_response(struct sk_buff *skb)
-{
- struct nlmsghdr *nlh = nlmsg_hdr(skb);
- struct ecryptfs_message *msg = NLMSG_DATA(nlh);
- struct pid *pid;
- int rc;
-
- if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) {
- rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Received netlink message with "
- "incorrectly specified data length\n");
- goto out;
- }
- pid = find_get_pid(NETLINK_CREDS(skb)->pid);
- rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid, NULL,
- pid, nlh->nlmsg_seq);
- put_pid(pid);
- if (rc)
- printk(KERN_ERR
- "Error processing response message; rc = [%d]\n", rc);
-out:
- return rc;
-}
-
-/**
- * ecryptfs_process_nl_helo
- * @skb: The socket buffer containing the nlmsghdr in HELO state
- *
- * Gets uid and pid of the skb and adds the values to the daemon id
- * hash. Returns zero after adding a new daemon id to the hash list;
- * non-zero otherwise.
- */
-static int ecryptfs_process_nl_helo(struct sk_buff *skb)
-{
- struct pid *pid;
- int rc;
-
- pid = find_get_pid(NETLINK_CREDS(skb)->pid);
- rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK,
- NETLINK_CREDS(skb)->uid, NULL, pid);
- put_pid(pid);
- if (rc)
- printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
- return rc;
-}
-
-/**
- * ecryptfs_process_nl_quit
- * @skb: The socket buffer containing the nlmsghdr in QUIT state
- *
- * Gets uid and pid of the skb and deletes the corresponding daemon
- * id, if it is the registered that is requesting the
- * deletion. Returns zero after deleting the desired daemon id;
- * non-zero otherwise.
- */
-static int ecryptfs_process_nl_quit(struct sk_buff *skb)
-{
- struct pid *pid;
- int rc;
-
- pid = find_get_pid(NETLINK_CREDS(skb)->pid);
- rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid, NULL, pid);
- put_pid(pid);
- if (rc)
- printk(KERN_WARNING
- "Error processing QUIT message; rc = [%d]\n", rc);
- return rc;
-}
-
-/**
- * ecryptfs_receive_nl_message
- *
- * Callback function called by netlink system when a message arrives.
- * If the message looks to be valid, then an attempt is made to assign
- * it to its desired netlink context element and wake up the process
- * that is waiting for a response.
- */
-static void ecryptfs_receive_nl_message(struct sk_buff *skb)
-{
- struct nlmsghdr *nlh;
-
- nlh = nlmsg_hdr(skb);
- if (!NLMSG_OK(nlh, skb->len)) {
- ecryptfs_printk(KERN_ERR, "Received corrupt netlink "
- "message\n");
- goto free;
- }
- switch (nlh->nlmsg_type) {
- case ECRYPTFS_MSG_RESPONSE:
- if (ecryptfs_process_nl_response(skb)) {
- ecryptfs_printk(KERN_WARNING, "Failed to "
- "deliver netlink response to "
- "requesting operation\n");
- }
- break;
- case ECRYPTFS_MSG_HELO:
- if (ecryptfs_process_nl_helo(skb)) {
- ecryptfs_printk(KERN_WARNING, "Failed to "
- "fulfill HELO request\n");
- }
- break;
- case ECRYPTFS_MSG_QUIT:
- if (ecryptfs_process_nl_quit(skb)) {
- ecryptfs_printk(KERN_WARNING, "Failed to "
- "fulfill QUIT request\n");
- }
- break;
- default:
- ecryptfs_printk(KERN_WARNING, "Dropping netlink "
- "message of unrecognized type [%d]\n",
- nlh->nlmsg_type);
- break;
- }
-free:
- kfree_skb(skb);
-}
-
-/**
- * ecryptfs_init_netlink
- *
- * Initializes the daemon id hash list, netlink context array, and
- * necessary locks. Returns zero upon success; non-zero upon error.
- */
-int ecryptfs_init_netlink(void)
-{
- int rc;
-
- ecryptfs_nl_sock = netlink_kernel_create(&init_net, NETLINK_ECRYPTFS, 0,
- ecryptfs_receive_nl_message,
- NULL, THIS_MODULE);
- if (!ecryptfs_nl_sock) {
- rc = -EIO;
- ecryptfs_printk(KERN_ERR, "Failed to create netlink socket\n");
- goto out;
- }
- ecryptfs_nl_sock->sk_sndtimeo = ECRYPTFS_DEFAULT_SEND_TIMEOUT;
- rc = 0;
-out:
- return rc;
-}
-
-/**
- * ecryptfs_release_netlink
- *
- * Frees all memory used by the netlink context array and releases the
- * netlink socket.
- */
-void ecryptfs_release_netlink(void)
-{
- netlink_kernel_release(ecryptfs_nl_sock);
- ecryptfs_nl_sock = NULL;
-}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 7cc0eb756b5..99368bda026 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -927,14 +927,11 @@ errxit:
/*
* During the time we spent in the loop above, some other events
* might have been queued by the poll callback. We re-insert them
- * here (in case they are not already queued, or they're one-shot).
+ * inside the main ready-list here.
*/
for (nepi = ep->ovflist; (epi = nepi) != NULL;
- nepi = epi->next, epi->next = EP_UNACTIVE_PTR) {
- if (!ep_is_linked(&epi->rdllink) &&
- (epi->event.events & ~EP_PRIVATE_BITS))
- list_add_tail(&epi->rdllink, &ep->rdllist);
- }
+ nepi = epi->next, epi->next = EP_UNACTIVE_PTR)
+ list_add_tail(&epi->rdllink, &ep->rdllist);
/*
* We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after
* releasing the lock, events will be queued in the normal way inside
diff --git a/fs/exec.c b/fs/exec.c
index cecee501ce7..cfb5656b2cd 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -391,7 +391,7 @@ static int count(char __user * __user * argv, int max)
if (!p)
break;
argv++;
- if(++i > max)
+ if (i++ >= max)
return -E2BIG;
cond_resched();
}
@@ -825,8 +825,6 @@ static int de_thread(struct task_struct *tsk)
schedule();
}
- if (unlikely(task_child_reaper(tsk) == leader))
- task_active_pid_ns(tsk)->child_reaper = tsk;
/*
* The only record we have of the real-time age of a
* process, regardless of execs it's done, is start_time.
@@ -1189,7 +1187,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
return retval;
/* Remember if the application is TASO. */
- bprm->sh_bang = eh->ah.entry < 0x100000000UL;
+ bprm->taso = eh->ah.entry < 0x100000000UL;
bprm->file = file;
bprm->loader = loader;
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 10bb02c3f25..6dac7ba2d22 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1295,6 +1295,7 @@ retry_alloc:
* turn off reservation for this allocation
*/
if (my_rsv && (free_blocks < windowsz)
+ && (free_blocks > 0)
&& (rsv_is_empty(&my_rsv->rsv_window)))
my_rsv = NULL;
@@ -1332,7 +1333,7 @@ retry_alloc:
* free blocks is less than half of the reservation
* window size.
*/
- if (free_blocks <= (windowsz/2))
+ if (my_rsv && (free_blocks <= (windowsz/2)))
continue;
brelse(bitmap_bh);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index a78c6b4af06..11a49ce8439 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -103,7 +103,7 @@ static int ext2_commit_chunk(struct page *page, loff_t pos, unsigned len)
return err;
}
-static void ext2_check_page(struct page *page)
+static void ext2_check_page(struct page *page, int quiet)
{
struct inode *dir = page->mapping->host;
struct super_block *sb = dir->i_sb;
@@ -146,10 +146,10 @@ out:
/* Too bad, we had an error */
Ebadsize:
- ext2_error(sb, "ext2_check_page",
- "size of directory #%lu is not a multiple of chunk size",
- dir->i_ino
- );
+ if (!quiet)
+ ext2_error(sb, __func__,
+ "size of directory #%lu is not a multiple "
+ "of chunk size", dir->i_ino);
goto fail;
Eshort:
error = "rec_len is smaller than minimal";
@@ -166,32 +166,36 @@ Espan:
Einumber:
error = "inode out of bounds";
bad_entry:
- ext2_error (sb, "ext2_check_page", "bad entry in directory #%lu: %s - "
- "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
- dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode),
- rec_len, p->name_len);
+ if (!quiet)
+ ext2_error(sb, __func__, "bad entry in directory #%lu: : %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode),
+ rec_len, p->name_len);
goto fail;
Eend:
- p = (ext2_dirent *)(kaddr + offs);
- ext2_error (sb, "ext2_check_page",
- "entry in directory #%lu spans the page boundary"
- "offset=%lu, inode=%lu",
- dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
- (unsigned long) le32_to_cpu(p->inode));
+ if (!quiet) {
+ p = (ext2_dirent *)(kaddr + offs);
+ ext2_error(sb, "ext2_check_page",
+ "entry in directory #%lu spans the page boundary"
+ "offset=%lu, inode=%lu",
+ dir->i_ino, (page->index<<PAGE_CACHE_SHIFT)+offs,
+ (unsigned long) le32_to_cpu(p->inode));
+ }
fail:
SetPageChecked(page);
SetPageError(page);
}
-static struct page * ext2_get_page(struct inode *dir, unsigned long n)
+static struct page * ext2_get_page(struct inode *dir, unsigned long n,
+ int quiet)
{
struct address_space *mapping = dir->i_mapping;
struct page *page = read_mapping_page(mapping, n, NULL);
if (!IS_ERR(page)) {
kmap(page);
if (!PageChecked(page))
- ext2_check_page(page);
+ ext2_check_page(page, quiet);
if (PageError(page))
goto fail;
}
@@ -292,7 +296,7 @@ ext2_readdir (struct file * filp, void * dirent, filldir_t filldir)
for ( ; n < npages; n++, offset = 0) {
char *kaddr, *limit;
ext2_dirent *de;
- struct page *page = ext2_get_page(inode, n);
+ struct page *page = ext2_get_page(inode, n, 0);
if (IS_ERR(page)) {
ext2_error(sb, __func__,
@@ -361,6 +365,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
struct page *page = NULL;
struct ext2_inode_info *ei = EXT2_I(dir);
ext2_dirent * de;
+ int dir_has_error = 0;
if (npages == 0)
goto out;
@@ -374,7 +379,7 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
n = start;
do {
char *kaddr;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, dir_has_error);
if (!IS_ERR(page)) {
kaddr = page_address(page);
de = (ext2_dirent *) kaddr;
@@ -391,7 +396,9 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir,
de = ext2_next_entry(de);
}
ext2_put_page(page);
- }
+ } else
+ dir_has_error = 1;
+
if (++n >= npages)
n = 0;
/* next page is past the blocks we've got */
@@ -414,7 +421,7 @@ found:
struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p)
{
- struct page *page = ext2_get_page(dir, 0);
+ struct page *page = ext2_get_page(dir, 0, 0);
ext2_dirent *de = NULL;
if (!IS_ERR(page)) {
@@ -487,7 +494,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode)
for (n = 0; n <= npages; n++) {
char *dir_end;
- page = ext2_get_page(dir, n);
+ page = ext2_get_page(dir, n, 0);
err = PTR_ERR(page);
if (IS_ERR(page))
goto out;
@@ -655,14 +662,17 @@ int ext2_empty_dir (struct inode * inode)
{
struct page *page = NULL;
unsigned long i, npages = dir_pages(inode);
+ int dir_has_error = 0;
for (i = 0; i < npages; i++) {
char *kaddr;
ext2_dirent * de;
- page = ext2_get_page(inode, i);
+ page = ext2_get_page(inode, i, dir_has_error);
- if (IS_ERR(page))
+ if (IS_ERR(page)) {
+ dir_has_error = 1;
continue;
+ }
kaddr = page_address(page);
de = (ext2_dirent *)kaddr;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 25adfc3c693..d0ff0b8cf30 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -8,7 +8,7 @@
* pages against inodes. ie: data writeback. Writeout of the
* inode itself is not handled here.
*
- * 10Apr2002 akpm@zip.com.au
+ * 10Apr2002 Andrew Morton
* Split out of fs/inode.c
* Additions for address_space-based writeback
*/
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index ba851576ebb..6d98f116ca0 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -190,6 +190,10 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
fd->search_key->cat.ParID = rec.thread.ParID;
len = fd->search_key->cat.CName.len = rec.thread.CName.len;
+ if (len > HFS_NAMELEN) {
+ printk(KERN_ERR "hfs: bad catalog namelength\n");
+ return -EIO;
+ }
memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
return hfs_brec_find(fd);
}
diff --git a/fs/hfsplus/bitmap.c b/fs/hfsplus/bitmap.c
index d128a25b74d..ea30afc2a03 100644
--- a/fs/hfsplus/bitmap.c
+++ b/fs/hfsplus/bitmap.c
@@ -32,6 +32,10 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
+ if (IS_ERR(page)) {
+ start = size;
+ goto out;
+ }
pptr = kmap(page);
curr = pptr + (offset & (PAGE_CACHE_BITS - 1)) / 32;
i = offset % 32;
@@ -73,6 +77,10 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
break;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
NULL);
+ if (IS_ERR(page)) {
+ start = size;
+ goto out;
+ }
curr = pptr = kmap(page);
if ((size ^ offset) / PAGE_CACHE_BITS)
end = pptr + PAGE_CACHE_BITS / 32;
@@ -120,6 +128,10 @@ found:
offset += PAGE_CACHE_BITS;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS,
NULL);
+ if (IS_ERR(page)) {
+ start = size;
+ goto out;
+ }
pptr = kmap(page);
curr = pptr;
end = pptr + PAGE_CACHE_BITS / 32;
diff --git a/fs/hfsplus/catalog.c b/fs/hfsplus/catalog.c
index ba117c445e7..f6874acb2cf 100644
--- a/fs/hfsplus/catalog.c
+++ b/fs/hfsplus/catalog.c
@@ -168,6 +168,11 @@ int hfsplus_find_cat(struct super_block *sb, u32 cnid,
return -EIO;
}
+ if (be16_to_cpu(tmp.thread.nodeName.length) > 255) {
+ printk(KERN_ERR "hfs: catalog name length corrupted\n");
+ return -EIO;
+ }
+
hfsplus_cat_build_key_uni(fd->search_key, be32_to_cpu(tmp.thread.parentID),
&tmp.thread.nodeName);
return hfs_brec_find(fd);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index e834e578c93..eb74531a0a8 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -356,7 +356,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_SOFTLOCK)) {
printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
- } else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
+ } else if ((vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) && !(sb->s_flags & MS_RDONLY)) {
printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
"use the force option at your own risk, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
diff --git a/fs/lockd/Makefile b/fs/lockd/Makefile
index 7725a0a9a55..97f6073ab33 100644
--- a/fs/lockd/Makefile
+++ b/fs/lockd/Makefile
@@ -5,6 +5,6 @@
obj-$(CONFIG_LOCKD) += lockd.o
lockd-objs-y := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
- svcproc.o svcsubs.o mon.o xdr.o
+ svcproc.o svcsubs.o mon.o xdr.o grace.o
lockd-objs-$(CONFIG_LOCKD_V4) += xdr4.o svc4proc.o
lockd-objs := $(lockd-objs-y)
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 0b45fd3a4bf..8307dd64bf4 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -54,14 +54,13 @@ struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init)
u32 nlm_version = (nlm_init->nfs_version == 2) ? 1 : 4;
int status;
- status = lockd_up(nlm_init->protocol);
+ status = lockd_up();
if (status < 0)
return ERR_PTR(status);
- host = nlmclnt_lookup_host((struct sockaddr_in *)nlm_init->address,
+ host = nlmclnt_lookup_host(nlm_init->address, nlm_init->addrlen,
nlm_init->protocol, nlm_version,
- nlm_init->hostname,
- strlen(nlm_init->hostname));
+ nlm_init->hostname);
if (host == NULL) {
lockd_down();
return ERR_PTR(-ENOLCK);
@@ -142,7 +141,7 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
/*
* The server lockd has called us back to tell us the lock was granted
*/
-__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
{
const struct file_lock *fl = &lock->fl;
const struct nfs_fh *fh = &lock->fh;
@@ -166,7 +165,7 @@ __be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock
*/
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue;
- if (!nlm_cmp_addr(&block->b_host->h_addr, addr))
+ if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue;
@@ -216,7 +215,7 @@ reclaimer(void *ptr)
/* This one ensures that our parent doesn't terminate while the
* reclaim is in progress */
lock_kernel();
- lockd_up(0); /* note: this cannot fail as lockd is already running */
+ lockd_up(); /* note: this cannot fail as lockd is already running */
dprintk("lockd: reclaiming locks for host %s\n", host->h_name);
diff --git a/fs/lockd/grace.c b/fs/lockd/grace.c
new file mode 100644
index 00000000000..183cc1f0af1
--- /dev/null
+++ b/fs/lockd/grace.c
@@ -0,0 +1,59 @@
+/*
+ * Common code for control of lockd and nfsv4 grace periods.
+ */
+
+#include <linux/module.h>
+#include <linux/lockd/bind.h>
+
+static LIST_HEAD(grace_list);
+static DEFINE_SPINLOCK(grace_lock);
+
+/**
+ * locks_start_grace
+ * @lm: who this grace period is for
+ *
+ * A grace period is a period during which locks should not be given
+ * out. Currently grace periods are only enforced by the two lock
+ * managers (lockd and nfsd), using the locks_in_grace() function to
+ * check when they are in a grace period.
+ *
+ * This function is called to start a grace period.
+ */
+void locks_start_grace(struct lock_manager *lm)
+{
+ spin_lock(&grace_lock);
+ list_add(&lm->list, &grace_list);
+ spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_start_grace);
+
+/**
+ * locks_end_grace
+ * @lm: who this grace period is for
+ *
+ * Call this function to state that the given lock manager is ready to
+ * resume regular locking. The grace period will not end until all lock
+ * managers that called locks_start_grace() also call locks_end_grace().
+ * Note that callers count on it being safe to call this more than once,
+ * and the second call should be a no-op.
+ */
+void locks_end_grace(struct lock_manager *lm)
+{
+ spin_lock(&grace_lock);
+ list_del_init(&lm->list);
+ spin_unlock(&grace_lock);
+}
+EXPORT_SYMBOL_GPL(locks_end_grace);
+
+/**
+ * locks_in_grace
+ *
+ * Lock managers call this function to determine when it is OK for them
+ * to answer ordinary lock requests, and when they should accept only
+ * lock reclaims.
+ */
+int locks_in_grace(void)
+{
+ return !list_empty(&grace_list);
+}
+EXPORT_SYMBOL_GPL(locks_in_grace);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index a17664c7eac..9fd8889097b 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -11,16 +11,17 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/in.h>
+#include <linux/in6.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
#include <linux/lockd/sm_inter.h>
#include <linux/mutex.h>
+#include <net/ipv6.h>
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE
#define NLM_HOST_NRHASH 32
-#define NLM_ADDRHASH(addr) (ntohl(addr) & (NLM_HOST_NRHASH-1))
#define NLM_HOST_REBIND (60 * HZ)
#define NLM_HOST_EXPIRE (300 * HZ)
#define NLM_HOST_COLLECT (120 * HZ)
@@ -30,42 +31,115 @@ static unsigned long next_gc;
static int nrhosts;
static DEFINE_MUTEX(nlm_host_mutex);
-
static void nlm_gc_hosts(void);
-static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
- const char *, unsigned int, int);
-static struct nsm_handle * nsm_find(const struct sockaddr_in *sin,
- const char *hostname,
- unsigned int hostname_len);
+static struct nsm_handle *nsm_find(const struct sockaddr *sap,
+ const size_t salen,
+ const char *hostname,
+ const size_t hostname_len,
+ const int create);
+
+struct nlm_lookup_host_info {
+ const int server; /* search for server|client */
+ const struct sockaddr *sap; /* address to search for */
+ const size_t salen; /* it's length */
+ const unsigned short protocol; /* transport to search for*/
+ const u32 version; /* NLM version to search for */
+ const char *hostname; /* remote's hostname */
+ const size_t hostname_len; /* it's length */
+ const struct sockaddr *src_sap; /* our address (optional) */
+ const size_t src_len; /* it's length */
+};
+
+/*
+ * Hash function must work well on big- and little-endian platforms
+ */
+static unsigned int __nlm_hash32(const __be32 n)
+{
+ unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
+ return hash ^ (hash >> 8);
+}
+
+static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
+{
+ const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ return __nlm_hash32(sin->sin_addr.s_addr);
+}
+
+static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
+{
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+ const struct in6_addr addr = sin6->sin6_addr;
+ return __nlm_hash32(addr.s6_addr32[0]) ^
+ __nlm_hash32(addr.s6_addr32[1]) ^
+ __nlm_hash32(addr.s6_addr32[2]) ^
+ __nlm_hash32(addr.s6_addr32[3]);
+}
+
+static unsigned int nlm_hash_address(const struct sockaddr *sap)
+{
+ unsigned int hash;
+
+ switch (sap->sa_family) {
+ case AF_INET:
+ hash = __nlm_hash_addr4(sap);
+ break;
+ case AF_INET6:
+ hash = __nlm_hash_addr6(sap);
+ break;
+ default:
+ hash = 0;
+ }
+ return hash & (NLM_HOST_NRHASH - 1);
+}
+
+static void nlm_clear_port(struct sockaddr *sap)
+{
+ switch (sap->sa_family) {
+ case AF_INET:
+ ((struct sockaddr_in *)sap)->sin_port = 0;
+ break;
+ case AF_INET6:
+ ((struct sockaddr_in6 *)sap)->sin6_port = 0;
+ break;
+ }
+}
+
+static void nlm_display_address(const struct sockaddr *sap,
+ char *buf, const size_t len)
+{
+ const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+
+ switch (sap->sa_family) {
+ case AF_UNSPEC:
+ snprintf(buf, len, "unspecified");
+ break;
+ case AF_INET:
+ snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr));
+ break;
+ case AF_INET6:
+ if (ipv6_addr_v4mapped(&sin6->sin6_addr))
+ snprintf(buf, len, NIPQUAD_FMT,
+ NIPQUAD(sin6->sin6_addr.s6_addr32[3]));
+ else
+ snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr));
+ break;
+ default:
+ snprintf(buf, len, "unsupported address family");
+ break;
+ }
+}
/*
* Common host lookup routine for server & client
*/
-static struct nlm_host *nlm_lookup_host(int server,
- const struct sockaddr_in *sin,
- int proto, u32 version,
- const char *hostname,
- unsigned int hostname_len,
- const struct sockaddr_in *ssin)
+static struct nlm_host *nlm_lookup_host(struct nlm_lookup_host_info *ni)
{
struct hlist_head *chain;
struct hlist_node *pos;
struct nlm_host *host;
struct nsm_handle *nsm = NULL;
- int hash;
-
- dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT
- ", p=%d, v=%u, my role=%s, name=%.*s)\n",
- NIPQUAD(ssin->sin_addr.s_addr),
- NIPQUAD(sin->sin_addr.s_addr), proto, version,
- server? "server" : "client",
- hostname_len,
- hostname? hostname : "<none>");
-
- hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
-
- /* Lock hash table */
mutex_lock(&nlm_host_mutex);
if (time_after_eq(jiffies, next_gc))
@@ -78,22 +152,22 @@ static struct nlm_host *nlm_lookup_host(int server,
* different NLM rpc_clients into one single nlm_host object.
* This would allow us to have one nlm_host per address.
*/
- chain = &nlm_hosts[hash];
+ chain = &nlm_hosts[nlm_hash_address(ni->sap)];
hlist_for_each_entry(host, pos, chain, h_hash) {
- if (!nlm_cmp_addr(&host->h_addr, sin))
+ if (!nlm_cmp_addr(nlm_addr(host), ni->sap))
continue;
/* See if we have an NSM handle for this client */
if (!nsm)
nsm = host->h_nsmhandle;
- if (host->h_proto != proto)
+ if (host->h_proto != ni->protocol)
continue;
- if (host->h_version != version)
+ if (host->h_version != ni->version)
continue;
- if (host->h_server != server)
+ if (host->h_server != ni->server)
continue;
- if (!nlm_cmp_addr(&host->h_saddr, ssin))
+ if (!nlm_cmp_addr(nlm_srcaddr(host), ni->src_sap))
continue;
/* Move to head of hash chain. */
@@ -101,30 +175,41 @@ static struct nlm_host *nlm_lookup_host(int server,
hlist_add_head(&host->h_hash, chain);
nlm_get_host(host);
+ dprintk("lockd: nlm_lookup_host found host %s (%s)\n",
+ host->h_name, host->h_addrbuf);
goto out;
}
- if (nsm)
- atomic_inc(&nsm->sm_count);
-
- host = NULL;
- /* Sadly, the host isn't in our hash table yet. See if
- * we have an NSM handle for it. If not, create one.
+ /*
+ * The host wasn't in our hash table. If we don't
+ * have an NSM handle for it yet, create one.
*/
- if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
- goto out;
+ if (nsm)
+ atomic_inc(&nsm->sm_count);
+ else {
+ host = NULL;
+ nsm = nsm_find(ni->sap, ni->salen,
+ ni->hostname, ni->hostname_len, 1);
+ if (!nsm) {
+ dprintk("lockd: nlm_lookup_host failed; "
+ "no nsm handle\n");
+ goto out;
+ }
+ }
host = kzalloc(sizeof(*host), GFP_KERNEL);
if (!host) {
nsm_release(nsm);
+ dprintk("lockd: nlm_lookup_host failed; no memory\n");
goto out;
}
host->h_name = nsm->sm_name;
- host->h_addr = *sin;
- host->h_addr.sin_port = 0; /* ouch! */
- host->h_saddr = *ssin;
- host->h_version = version;
- host->h_proto = proto;
+ memcpy(nlm_addr(host), ni->sap, ni->salen);
+ host->h_addrlen = ni->salen;
+ nlm_clear_port(nlm_addr(host));
+ memcpy(nlm_srcaddr(host), ni->src_sap, ni->src_len);
+ host->h_version = ni->version;
+ host->h_proto = ni->protocol;
host->h_rpcclnt = NULL;
mutex_init(&host->h_mutex);
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
@@ -135,7 +220,7 @@ static struct nlm_host *nlm_lookup_host(int server,
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
host->h_nsmhandle = nsm;
- host->h_server = server;
+ host->h_server = ni->server;
hlist_add_head(&host->h_hash, chain);
INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock);
@@ -143,6 +228,15 @@ static struct nlm_host *nlm_lookup_host(int server,
INIT_LIST_HEAD(&host->h_reclaim);
nrhosts++;
+
+ nlm_display_address((struct sockaddr *)&host->h_addr,
+ host->h_addrbuf, sizeof(host->h_addrbuf));
+ nlm_display_address((struct sockaddr *)&host->h_srcaddr,
+ host->h_srcaddrbuf, sizeof(host->h_srcaddrbuf));
+
+ dprintk("lockd: nlm_lookup_host created host %s\n",
+ host->h_name);
+
out:
mutex_unlock(&nlm_host_mutex);
return host;
@@ -170,33 +264,103 @@ nlm_destroy_host(struct nlm_host *host)
kfree(host);
}
-/*
- * Find an NLM server handle in the cache. If there is none, create it.
+/**
+ * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
+ * @sap: network address of server
+ * @salen: length of server address
+ * @protocol: transport protocol to use
+ * @version: NLM protocol version
+ * @hostname: '\0'-terminated hostname of server
+ *
+ * Returns an nlm_host structure that matches the passed-in
+ * [server address, transport protocol, NLM version, server hostname].
+ * If one doesn't already exist in the host cache, a new handle is
+ * created and returned.
*/
-struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
- int proto, u32 version,
- const char *hostname,
- unsigned int hostname_len)
+struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
+ const size_t salen,
+ const unsigned short protocol,
+ const u32 version, const char *hostname)
{
- struct sockaddr_in ssin = {0};
-
- return nlm_lookup_host(0, sin, proto, version,
- hostname, hostname_len, &ssin);
+ const struct sockaddr source = {
+ .sa_family = AF_UNSPEC,
+ };
+ struct nlm_lookup_host_info ni = {
+ .server = 0,
+ .sap = sap,
+ .salen = salen,
+ .protocol = protocol,
+ .version = version,
+ .hostname = hostname,
+ .hostname_len = strlen(hostname),
+ .src_sap = &source,
+ .src_len = sizeof(source),
+ };
+
+ dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
+ (hostname ? hostname : "<none>"), version,
+ (protocol == IPPROTO_UDP ? "udp" : "tcp"));
+
+ return nlm_lookup_host(&ni);
}
-/*
- * Find an NLM client handle in the cache. If there is none, create it.
+/**
+ * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
+ * @rqstp: incoming NLM request
+ * @hostname: name of client host
+ * @hostname_len: length of client hostname
+ *
+ * Returns an nlm_host structure that matches the [client address,
+ * transport protocol, NLM version, client hostname] of the passed-in
+ * NLM request. If one doesn't already exist in the host cache, a
+ * new handle is created and returned.
+ *
+ * Before possibly creating a new nlm_host, construct a sockaddr
+ * for a specific source address in case the local system has
+ * multiple network addresses. The family of the address in
+ * rq_daddr is guaranteed to be the same as the family of the
+ * address in rq_addr, so it's safe to use the same family for
+ * the source address.
*/
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp,
- const char *hostname, unsigned int hostname_len)
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
+ const char *hostname,
+ const size_t hostname_len)
{
- struct sockaddr_in ssin = {0};
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ };
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ };
+ struct nlm_lookup_host_info ni = {
+ .server = 1,
+ .sap = svc_addr(rqstp),
+ .salen = rqstp->rq_addrlen,
+ .protocol = rqstp->rq_prot,
+ .version = rqstp->rq_vers,
+ .hostname = hostname,
+ .hostname_len = hostname_len,
+ .src_len = rqstp->rq_addrlen,
+ };
+
+ dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
+ (int)hostname_len, hostname, rqstp->rq_vers,
+ (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
+
+ switch (ni.sap->sa_family) {
+ case AF_INET:
+ sin.sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
+ ni.src_sap = (struct sockaddr *)&sin;
+ break;
+ case AF_INET6:
+ ipv6_addr_copy(&sin6.sin6_addr, &rqstp->rq_daddr.addr6);
+ ni.src_sap = (struct sockaddr *)&sin6;
+ break;
+ default:
+ return NULL;
+ }
- ssin.sin_addr = rqstp->rq_daddr.addr;
- return nlm_lookup_host(1, svc_addr_in(rqstp),
- rqstp->rq_prot, rqstp->rq_vers,
- hostname, hostname_len, &ssin);
+ return nlm_lookup_host(&ni);
}
/*
@@ -207,9 +371,8 @@ nlm_bind_host(struct nlm_host *host)
{
struct rpc_clnt *clnt;
- dprintk("lockd: nlm_bind_host("NIPQUAD_FMT"->"NIPQUAD_FMT")\n",
- NIPQUAD(host->h_saddr.sin_addr),
- NIPQUAD(host->h_addr.sin_addr));
+ dprintk("lockd: nlm_bind_host %s (%s), my addr=%s\n",
+ host->h_name, host->h_addrbuf, host->h_srcaddrbuf);
/* Lock host handle */
mutex_lock(&host->h_mutex);
@@ -221,7 +384,7 @@ nlm_bind_host(struct nlm_host *host)
if (time_after_eq(jiffies, host->h_nextrebind)) {
rpc_force_rebind(clnt);
host->h_nextrebind = jiffies + NLM_HOST_REBIND;
- dprintk("lockd: next rebind in %ld jiffies\n",
+ dprintk("lockd: next rebind in %lu jiffies\n",
host->h_nextrebind - jiffies);
}
} else {
@@ -234,9 +397,9 @@ nlm_bind_host(struct nlm_host *host)
};
struct rpc_create_args args = {
.protocol = host->h_proto,
- .address = (struct sockaddr *)&host->h_addr,
- .addrsize = sizeof(host->h_addr),
- .saddress = (struct sockaddr *)&host->h_saddr,
+ .address = nlm_addr(host),
+ .addrsize = host->h_addrlen,
+ .saddress = nlm_srcaddr(host),
.timeout = &timeparms,
.servername = host->h_name,
.program = &nlm_program,
@@ -324,12 +487,16 @@ void nlm_host_rebooted(const struct sockaddr_in *sin,
struct nsm_handle *nsm;
struct nlm_host *host;
- dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
- hostname, NIPQUAD(sin->sin_addr));
-
- /* Find the NSM handle for this peer */
- if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
+ nsm = nsm_find((struct sockaddr *)sin, sizeof(*sin),
+ hostname, hostname_len, 0);
+ if (nsm == NULL) {
+ dprintk("lockd: never saw rebooted peer '%.*s' before\n",
+ hostname_len, hostname);
return;
+ }
+
+ dprintk("lockd: nlm_host_rebooted(%.*s, %s)\n",
+ hostname_len, hostname, nsm->sm_addrbuf);
/* When reclaiming locks on this peer, make sure that
* we set up a new notification */
@@ -461,22 +628,23 @@ nlm_gc_hosts(void)
static LIST_HEAD(nsm_handles);
static DEFINE_SPINLOCK(nsm_lock);
-static struct nsm_handle *
-__nsm_find(const struct sockaddr_in *sin,
- const char *hostname, unsigned int hostname_len,
- int create)
+static struct nsm_handle *nsm_find(const struct sockaddr *sap,
+ const size_t salen,
+ const char *hostname,
+ const size_t hostname_len,
+ const int create)
{
struct nsm_handle *nsm = NULL;
struct nsm_handle *pos;
- if (!sin)
+ if (!sap)
return NULL;
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
if (printk_ratelimit()) {
printk(KERN_WARNING "Invalid hostname \"%.*s\" "
"in NFS lock request\n",
- hostname_len, hostname);
+ (int)hostname_len, hostname);
}
return NULL;
}
@@ -489,7 +657,7 @@ retry:
if (strlen(pos->sm_name) != hostname_len
|| memcmp(pos->sm_name, hostname, hostname_len))
continue;
- } else if (!nlm_cmp_addr(&pos->sm_addr, sin))
+ } else if (!nlm_cmp_addr(nsm_addr(pos), sap))
continue;
atomic_inc(&pos->sm_count);
kfree(nsm);
@@ -509,10 +677,13 @@ retry:
if (nsm == NULL)
return NULL;
- nsm->sm_addr = *sin;
+ memcpy(nsm_addr(nsm), sap, salen);
+ nsm->sm_addrlen = salen;
nsm->sm_name = (char *) (nsm + 1);
memcpy(nsm->sm_name, hostname, hostname_len);
nsm->sm_name[hostname_len] = '\0';
+ nlm_display_address((struct sockaddr *)&nsm->sm_addr,
+ nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
atomic_set(&nsm->sm_count, 1);
goto retry;
@@ -521,13 +692,6 @@ found:
return nsm;
}
-static struct nsm_handle *
-nsm_find(const struct sockaddr_in *sin, const char *hostname,
- unsigned int hostname_len)
-{
- return __nsm_find(sin, hostname, hostname_len, 1);
-}
-
/*
* Release an NSM handle
*/
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index e4d563543b1..4e7e958e8f6 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -51,7 +51,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
memset(&args, 0, sizeof(args));
args.mon_name = nsm->sm_name;
- args.addr = nsm->sm_addr.sin_addr.s_addr;
+ args.addr = nsm_addr_in(nsm)->sin_addr.s_addr;
args.prog = NLM_PROGRAM;
args.vers = 3;
args.proc = NLMPROC_NSM_NOTIFY;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 5bd9bf0fa9d..c631a83931c 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -51,7 +51,6 @@ static DEFINE_MUTEX(nlmsvc_mutex);
static unsigned int nlmsvc_users;
static struct task_struct *nlmsvc_task;
static struct svc_rqst *nlmsvc_rqst;
-int nlmsvc_grace_period;
unsigned long nlmsvc_timeout;
/*
@@ -85,27 +84,23 @@ static unsigned long get_lockd_grace_period(void)
return nlm_timeout * 5 * HZ;
}
-unsigned long get_nfs_grace_period(void)
-{
- unsigned long lockdgrace = get_lockd_grace_period();
- unsigned long nfsdgrace = 0;
-
- if (nlmsvc_ops)
- nfsdgrace = nlmsvc_ops->get_grace_period();
-
- return max(lockdgrace, nfsdgrace);
-}
-EXPORT_SYMBOL(get_nfs_grace_period);
+static struct lock_manager lockd_manager = {
+};
-static unsigned long set_grace_period(void)
+static void grace_ender(struct work_struct *not_used)
{
- nlmsvc_grace_period = 1;
- return get_nfs_grace_period() + jiffies;
+ locks_end_grace(&lockd_manager);
}
-static inline void clear_grace_period(void)
+static DECLARE_DELAYED_WORK(grace_period_end, grace_ender);
+
+static void set_grace_period(void)
{
- nlmsvc_grace_period = 0;
+ unsigned long grace_period = get_lockd_grace_period();
+
+ locks_start_grace(&lockd_manager);
+ cancel_delayed_work_sync(&grace_period_end);
+ schedule_delayed_work(&grace_period_end, grace_period);
}
/*
@@ -116,7 +111,6 @@ lockd(void *vrqstp)
{
int err = 0, preverr = 0;
struct svc_rqst *rqstp = vrqstp;
- unsigned long grace_period_expire;
/* try_to_freeze() is called from svc_recv() */
set_freezable();
@@ -139,7 +133,7 @@ lockd(void *vrqstp)
nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ;
- grace_period_expire = set_grace_period();
+ set_grace_period();
/*
* The main request loop. We don't terminate until the last
@@ -153,21 +147,12 @@ lockd(void *vrqstp)
flush_signals(current);
if (nlmsvc_ops) {
nlmsvc_invalidate_all();
- grace_period_expire = set_grace_period();
+ set_grace_period();
}
continue;
}
- /*
- * Retry any blocked locks that have been notified by
- * the VFS. Don't do this during grace period.
- * (Theoretically, there shouldn't even be blocked locks
- * during grace period).
- */
- if (!nlmsvc_grace_period) {
- timeout = nlmsvc_retry_blocked();
- } else if (time_before(grace_period_expire, jiffies))
- clear_grace_period();
+ timeout = nlmsvc_retry_blocked();
/*
* Find a socket with data available and call its
@@ -195,6 +180,7 @@ lockd(void *vrqstp)
svc_process(rqstp);
}
flush_signals(current);
+ cancel_delayed_work_sync(&grace_period_end);
if (nlmsvc_ops)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
@@ -203,25 +189,28 @@ lockd(void *vrqstp)
}
/*
- * Make any sockets that are needed but not present.
- * If nlm_udpport or nlm_tcpport were set as module
- * options, make those sockets unconditionally
+ * Ensure there are active UDP and TCP listeners for lockd.
+ *
+ * Even if we have only TCP NFS mounts and/or TCP NFSDs, some
+ * local services (such as rpc.statd) still require UDP, and
+ * some NFS servers do not yet support NLM over TCP.
+ *
+ * Returns zero if all listeners are available; otherwise a
+ * negative errno value is returned.
*/
-static int make_socks(struct svc_serv *serv, int proto)
+static int make_socks(struct svc_serv *serv)
{
static int warned;
struct svc_xprt *xprt;
int err = 0;
- if (proto == IPPROTO_UDP || nlm_udpport) {
- xprt = svc_find_xprt(serv, "udp", 0, 0);
- if (!xprt)
- err = svc_create_xprt(serv, "udp", nlm_udpport,
- SVC_SOCK_DEFAULTS);
- else
- svc_xprt_put(xprt);
- }
- if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) {
+ xprt = svc_find_xprt(serv, "udp", 0, 0);
+ if (!xprt)
+ err = svc_create_xprt(serv, "udp", nlm_udpport,
+ SVC_SOCK_DEFAULTS);
+ else
+ svc_xprt_put(xprt);
+ if (err >= 0) {
xprt = svc_find_xprt(serv, "tcp", 0, 0);
if (!xprt)
err = svc_create_xprt(serv, "tcp", nlm_tcpport,
@@ -241,8 +230,7 @@ static int make_socks(struct svc_serv *serv, int proto)
/*
* Bring up the lockd process if it's not already up.
*/
-int
-lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
+int lockd_up(void)
{
struct svc_serv *serv;
int error = 0;
@@ -251,11 +239,8 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
/*
* Check whether we're already up and running.
*/
- if (nlmsvc_rqst) {
- if (proto)
- error = make_socks(nlmsvc_rqst->rq_server, proto);
+ if (nlmsvc_rqst)
goto out;
- }
/*
* Sanity check: if there's no pid,
@@ -266,13 +251,14 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
"lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
+ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
goto out;
}
- if ((error = make_socks(serv, proto)) < 0)
+ error = make_socks(serv);
+ if (error < 0)
goto destroy_and_out;
/*
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index 4a714f64515..014f6ce4817 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -88,12 +88,6 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
dprintk("lockd: TEST4 called\n");
resp->cookie = argp->cookie;
- /* Don't accept test requests during grace period */
- if (nlmsvc_grace_period) {
- resp->status = nlm_lck_denied_grace_period;
- return rc;
- }
-
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -122,12 +116,6 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
- /* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period && !argp->reclaim) {
- resp->status = nlm_lck_denied_grace_period;
- return rc;
- }
-
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -146,7 +134,8 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
- argp->block, &argp->cookie);
+ argp->block, &argp->cookie,
+ argp->reclaim);
if (resp->status == nlm_drop_reply)
rc = rpc_drop_reply;
else
@@ -169,7 +158,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -202,7 +191,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -231,7 +220,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
dprintk("lockd: GRANTED called\n");
- resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+ resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
return rpc_success;
}
@@ -341,7 +330,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period && !argp->reclaim) {
+ if (locks_in_grace() && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -374,7 +363,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -432,11 +421,9 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
{
struct sockaddr_in saddr;
- memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
dprintk("lockd: SM_NOTIFY called\n");
- if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
- || ntohs(saddr.sin_port) >= 1024) {
+
+ if (!nlm_privileged_requester(rqstp)) {
char buf[RPC_MAX_ADDRBUFLEN];
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
svc_print_addr(rqstp, buf, sizeof(buf)));
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index cf0d5c2c318..6063a8e4b9f 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -360,7 +360,7 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
__be32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_host *host, struct nlm_lock *lock, int wait,
- struct nlm_cookie *cookie)
+ struct nlm_cookie *cookie, int reclaim)
{
struct nlm_block *block = NULL;
int error;
@@ -406,6 +406,15 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out;
}
+ if (locks_in_grace() && !reclaim) {
+ ret = nlm_lck_denied_grace_period;
+ goto out;
+ }
+ if (reclaim && !locks_in_grace()) {
+ ret = nlm_lck_denied_grace_period;
+ goto out;
+ }
+
if (!wait)
lock->fl.fl_flags &= ~FL_SLEEP;
error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
@@ -502,6 +511,10 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out;
}
+ if (locks_in_grace()) {
+ ret = nlm_lck_denied_grace_period;
+ goto out;
+ }
error = vfs_test_lock(file->f_file, &lock->fl);
if (error == FILE_LOCK_DEFERRED) {
ret = nlmsvc_defer_lock_rqst(rqstp, block);
@@ -582,6 +595,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
+ if (locks_in_grace())
+ return nlm_lck_denied_grace_period;
+
mutex_lock(&file->f_mutex);
block = nlmsvc_lookup_block(file, lock);
mutex_unlock(&file->f_mutex);
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 76262c1986f..548b0bb2b84 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -117,12 +117,6 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
dprintk("lockd: TEST called\n");
resp->cookie = argp->cookie;
- /* Don't accept test requests during grace period */
- if (nlmsvc_grace_period) {
- resp->status = nlm_lck_denied_grace_period;
- return rc;
- }
-
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -152,12 +146,6 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
- /* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period && !argp->reclaim) {
- resp->status = nlm_lck_denied_grace_period;
- return rc;
- }
-
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
@@ -176,7 +164,8 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Now try to lock the file */
resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock,
- argp->block, &argp->cookie));
+ argp->block, &argp->cookie,
+ argp->reclaim));
if (resp->status == nlm_drop_reply)
rc = rpc_drop_reply;
else
@@ -199,7 +188,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -232,7 +221,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -261,7 +250,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
dprintk("lockd: GRANTED called\n");
- resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock);
+ resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
dprintk("lockd: GRANTED status %d\n", ntohl(resp->status));
return rpc_success;
}
@@ -373,7 +362,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */
- if (nlmsvc_grace_period && !argp->reclaim) {
+ if (locks_in_grace() && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -406,7 +395,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie;
/* Don't accept requests during grace period */
- if (nlmsvc_grace_period) {
+ if (locks_in_grace()) {
resp->status = nlm_lck_denied_grace_period;
return rpc_success;
}
@@ -464,11 +453,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
{
struct sockaddr_in saddr;
- memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr));
-
dprintk("lockd: SM_NOTIFY called\n");
- if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
- || ntohs(saddr.sin_port) >= 1024) {
+
+ if (!nlm_privileged_requester(rqstp)) {
char buf[RPC_MAX_ADDRBUFLEN];
printk(KERN_WARNING "lockd: rejected NSM callback from %s\n",
svc_print_addr(rqstp, buf, sizeof(buf)));
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 198b4e55b37..34c2766e27c 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -418,7 +418,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_unlock_all_by_sb);
static int
nlmsvc_match_ip(void *datap, struct nlm_host *host)
{
- return nlm_cmp_addr(&host->h_saddr, datap);
+ return nlm_cmp_addr(nlm_srcaddr(host), datap);
}
/**
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 3e459e18cc3..1f226290c67 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -351,8 +351,6 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
argp->state = ntohl(*p++);
/* Preserve the address in network byte order */
argp->addr = *p++;
- argp->vers = *p++;
- argp->proto = *p++;
return xdr_argsize_check(rqstp, p);
}
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 43ff9397e6c..50c493a8ad8 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -358,8 +358,6 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp
argp->state = ntohl(*p++);
/* Preserve the address in network byte order */
argp->addr = *p++;
- argp->vers = *p++;
- argp->proto = *p++;
return xdr_argsize_check(rqstp, p);
}
diff --git a/fs/mpage.c b/fs/mpage.c
index dbcc7af76a1..552b80b3fac 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -6,7 +6,7 @@
* Contains functions related to preparing and submitting BIOs which contain
* multiple pagecache pages.
*
- * 15May2002 akpm@zip.com.au
+ * 15May2002 Andrew Morton
* Initial version
* 27Jun2002 axboe@suse.de
* use bio_add_page() to build bio's just the right size
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index f447f4b4476..6a09760c596 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -105,7 +105,8 @@ int nfs_callback_up(void)
mutex_lock(&nfs_callback_mutex);
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
goto out;
- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
+ AF_INET, NULL);
ret = -ENOMEM;
if (!serv)
goto out_err;
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 15c6faeec77..b2786a5f9af 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -70,7 +70,6 @@ nlm_fclose(struct file *filp)
static struct nlmsvc_binding nfsd_nlm_ops = {
.fopen = nlm_fopen, /* open file for locking */
.fclose = nlm_fclose, /* close file */
- .get_grace_period = get_nfs4_grace_period,
};
void
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index 4d617ea28cf..9dbd2eb9128 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -63,7 +63,8 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+ nfserr = fh_verify(rqstp, &resp->fh, 0,
+ NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
if (nfserr)
RETURN_STATUS(nfserr);
@@ -530,7 +531,7 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
dprintk("nfsd: FSSTAT(3) %s\n",
SVCFH_fmt(&argp->fh));
- nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+ nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
fh_put(&argp->fh);
RETURN_STATUS(nfserr);
}
@@ -558,7 +559,8 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
resp->f_maxfilesize = ~(u32) 0;
resp->f_properties = NFS3_FSF_DEFAULT;
- nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
+ nfserr = fh_verify(rqstp, &argp->fh, 0,
+ NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
/* Check special features of the file system. May request
* different read/write sizes for file systems known to have
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 702fa577aa6..094747a1227 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -225,7 +225,8 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
WRITE32(OP_CB_RECALL);
- WRITEMEM(&cb_rec->cbr_stateid, sizeof(stateid_t));
+ WRITE32(cb_rec->cbr_stateid.si_generation);
+ WRITEMEM(&cb_rec->cbr_stateid.si_opaque, sizeof(stateid_opaque_t));
WRITE32(cb_rec->cbr_trunc);
WRITE32(len);
WRITEMEM(cb_rec->cbr_fhval, len);
@@ -379,6 +380,7 @@ static int do_probe_callback(void *data)
.addrsize = sizeof(addr),
.timeout = &timeparms,
.program = &cb_program,
+ .prognumber = cb->cb_prog,
.version = nfs_cb_version[1]->number,
.authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */
.flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
@@ -396,9 +398,6 @@ static int do_probe_callback(void *data)
addr.sin_port = htons(cb->cb_port);
addr.sin_addr.s_addr = htonl(cb->cb_addr);
- /* Initialize rpc_stat */
- memset(args.program->stats, 0, sizeof(struct rpc_stat));
-
/* Create RPC client */
client = rpc_create(&args);
if (IS_ERR(client)) {
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e5b51ffafc6..669461e291a 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -201,10 +201,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* Openowner is now set, so sequence id will get bumped. Now we need
* these checks before we do any creates: */
status = nfserr_grace;
- if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
goto out;
status = nfserr_no_grace;
- if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
goto out;
switch (open->op_claim_type) {
@@ -575,7 +575,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{
__be32 status;
- if (nfs4_in_grace())
+ if (locks_in_grace())
return nfserr_grace;
status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
remove->rm_name, remove->rm_namelen);
@@ -596,7 +596,7 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (!cstate->save_fh.fh_dentry)
return status;
- if (nfs4_in_grace() && !(cstate->save_fh.fh_export->ex_flags
+ if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
& NFSEXP_NOSUBTREECHECK))
return nfserr_grace;
status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 1578d7a2667..0cc7ff5d5ab 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -61,7 +61,6 @@
static time_t lease_time = 90; /* default lease time */
static time_t user_lease_time = 90;
static time_t boot_time;
-static int in_grace = 1;
static u32 current_ownerid = 1;
static u32 current_fileid = 1;
static u32 current_delegid = 1;
@@ -1640,7 +1639,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
case NFS4_OPEN_CLAIM_NULL:
/* Let's not give out any delegations till everyone's
* had the chance to reclaim theirs.... */
- if (nfs4_in_grace())
+ if (locks_in_grace())
goto out;
if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
goto out;
@@ -1816,12 +1815,15 @@ out:
return status;
}
+struct lock_manager nfsd4_manager = {
+};
+
static void
-end_grace(void)
+nfsd4_end_grace(void)
{
dprintk("NFSD: end of grace period\n");
nfsd4_recdir_purge_old();
- in_grace = 0;
+ locks_end_grace(&nfsd4_manager);
}
static time_t
@@ -1838,8 +1840,8 @@ nfs4_laundromat(void)
nfs4_lock_state();
dprintk("NFSD: laundromat service - starting\n");
- if (in_grace)
- end_grace();
+ if (locks_in_grace())
+ nfsd4_end_grace();
list_for_each_safe(pos, next, &client_lru) {
clp = list_entry(pos, struct nfs4_client, cl_lru);
if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -1974,7 +1976,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
return nfserr_bad_stateid;
else if (ONE_STATEID(stateid) && (flags & RD_STATE))
return nfs_ok;
- else if (nfs4_in_grace()) {
+ else if (locks_in_grace()) {
/* Answer in remaining cases depends on existance of
* conflicting state; so we must wait out the grace period. */
return nfserr_grace;
@@ -1993,7 +1995,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
static inline int
io_during_grace_disallowed(struct inode *inode, int flags)
{
- return nfs4_in_grace() && (flags & (RD_STATE | WR_STATE))
+ return locks_in_grace() && (flags & (RD_STATE | WR_STATE))
&& mandatory_lock(inode);
}
@@ -2693,10 +2695,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
filp = lock_stp->st_vfs_file;
status = nfserr_grace;
- if (nfs4_in_grace() && !lock->lk_reclaim)
+ if (locks_in_grace() && !lock->lk_reclaim)
goto out;
status = nfserr_no_grace;
- if (!nfs4_in_grace() && lock->lk_reclaim)
+ if (!locks_in_grace() && lock->lk_reclaim)
goto out;
locks_init_lock(&file_lock);
@@ -2779,7 +2781,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
int error;
__be32 status;
- if (nfs4_in_grace())
+ if (locks_in_grace())
return nfserr_grace;
if (check_lock_length(lockt->lt_offset, lockt->lt_length))
@@ -3192,9 +3194,9 @@ __nfs4_state_start(void)
unsigned long grace_time;
boot_time = get_seconds();
- grace_time = get_nfs_grace_period();
+ grace_time = get_nfs4_grace_period();
lease_time = user_lease_time;
- in_grace = 1;
+ locks_start_grace(&nfsd4_manager);
printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
grace_time/HZ);
laundry_wq = create_singlethread_workqueue("nfsd4");
@@ -3213,12 +3215,6 @@ nfs4_state_start(void)
return;
}
-int
-nfs4_in_grace(void)
-{
- return in_grace;
-}
-
time_t
nfs4_lease_time(void)
{
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 14ba4d9b285..afcdf4b7684 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -413,6 +413,18 @@ out_nfserr:
}
static __be32
+nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid)
+{
+ DECODE_HEAD;
+
+ READ_BUF(sizeof(stateid_t));
+ READ32(sid->si_generation);
+ COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
{
DECODE_HEAD;
@@ -429,10 +441,9 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
DECODE_HEAD;
close->cl_stateowner = NULL;
- READ_BUF(4 + sizeof(stateid_t));
+ READ_BUF(4);
READ32(close->cl_seqid);
- READ32(close->cl_stateid.si_generation);
- COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
+ return nfsd4_decode_stateid(argp, &close->cl_stateid);
DECODE_TAIL;
}
@@ -493,13 +504,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
static inline __be32
nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
{
- DECODE_HEAD;
-
- READ_BUF(sizeof(stateid_t));
- READ32(dr->dr_stateid.si_generation);
- COPYMEM(&dr->dr_stateid.si_opaque, sizeof(stateid_opaque_t));
-
- DECODE_TAIL;
+ return nfsd4_decode_stateid(argp, &dr->dr_stateid);
}
static inline __be32
@@ -542,20 +547,22 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
READ32(lock->lk_is_new);
if (lock->lk_is_new) {
- READ_BUF(36);
+ READ_BUF(4);
READ32(lock->lk_new_open_seqid);
- READ32(lock->lk_new_open_stateid.si_generation);
-
- COPYMEM(&lock->lk_new_open_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid);
+ if (status)
+ return status;
+ READ_BUF(8 + sizeof(clientid_t));
READ32(lock->lk_new_lock_seqid);
COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t));
READ32(lock->lk_new_owner.len);
READ_BUF(lock->lk_new_owner.len);
READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len);
} else {
- READ_BUF(20);
- READ32(lock->lk_old_lock_stateid.si_generation);
- COPYMEM(&lock->lk_old_lock_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid);
+ if (status)
+ return status;
+ READ_BUF(4);
READ32(lock->lk_old_lock_seqid);
}
@@ -587,13 +594,15 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
DECODE_HEAD;
locku->lu_stateowner = NULL;
- READ_BUF(24 + sizeof(stateid_t));
+ READ_BUF(8);
READ32(locku->lu_type);
if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
goto xdr_error;
READ32(locku->lu_seqid);
- READ32(locku->lu_stateid.si_generation);
- COPYMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &locku->lu_stateid);
+ if (status)
+ return status;
+ READ_BUF(16);
READ64(locku->lu_offset);
READ64(locku->lu_length);
@@ -678,8 +687,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
READ32(open->op_delegate_type);
break;
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
- READ_BUF(sizeof(stateid_t) + 4);
- COPYMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+ status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid);
+ if (status)
+ return status;
+ READ_BUF(4);
READ32(open->op_fname.len);
READ_BUF(open->op_fname.len);
SAVEMEM(open->op_fname.data, open->op_fname.len);
@@ -699,9 +710,10 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
DECODE_HEAD;
open_conf->oc_stateowner = NULL;
- READ_BUF(4 + sizeof(stateid_t));
- READ32(open_conf->oc_req_stateid.si_generation);
- COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid);
+ if (status)
+ return status;
+ READ_BUF(4);
READ32(open_conf->oc_seqid);
DECODE_TAIL;
@@ -713,9 +725,10 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
DECODE_HEAD;
open_down->od_stateowner = NULL;
- READ_BUF(12 + sizeof(stateid_t));
- READ32(open_down->od_stateid.si_generation);
- COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &open_down->od_stateid);
+ if (status)
+ return status;
+ READ_BUF(12);
READ32(open_down->od_seqid);
READ32(open_down->od_share_access);
READ32(open_down->od_share_deny);
@@ -743,9 +756,10 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
{
DECODE_HEAD;
- READ_BUF(sizeof(stateid_t) + 12);
- READ32(read->rd_stateid.si_generation);
- COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &read->rd_stateid);
+ if (status)
+ return status;
+ READ_BUF(12);
READ64(read->rd_offset);
READ32(read->rd_length);
@@ -834,15 +848,13 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp,
static __be32
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
{
- DECODE_HEAD;
-
- READ_BUF(sizeof(stateid_t));
- READ32(setattr->sa_stateid.si_generation);
- COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
- if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
- goto out;
+ __be32 status;
- DECODE_TAIL;
+ status = nfsd4_decode_stateid(argp, &setattr->sa_stateid);
+ if (status)
+ return status;
+ return nfsd4_decode_fattr(argp, setattr->sa_bmval,
+ &setattr->sa_iattr, &setattr->sa_acl);
}
static __be32
@@ -927,9 +939,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
int len;
DECODE_HEAD;
- READ_BUF(sizeof(stateid_opaque_t) + 20);
- READ32(write->wr_stateid.si_generation);
- COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
+ status = nfsd4_decode_stateid(argp, &write->wr_stateid);
+ if (status)
+ return status;
+ READ_BUF(16);
READ64(write->wr_offset);
READ32(write->wr_stable_how);
if (write->wr_stable_how > 2)
@@ -1183,7 +1196,6 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
* Header routine to setup seqid operation replay cache
*/
#define ENCODE_SEQID_OP_HEAD \
- __be32 *p; \
__be32 *save; \
\
save = resp->p;
@@ -1950,6 +1962,17 @@ fail:
return -EINVAL;
}
+static void
+nfsd4_encode_stateid(struct nfsd4_compoundres *resp, stateid_t *sid)
+{
+ ENCODE_HEAD;
+
+ RESERVE_SPACE(sizeof(stateid_t));
+ WRITE32(sid->si_generation);
+ WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
+ ADJUST_ARGS();
+}
+
static __be32
nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
{
@@ -1969,12 +1992,9 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c
{
ENCODE_SEQID_OP_HEAD;
- if (!nfserr) {
- RESERVE_SPACE(sizeof(stateid_t));
- WRITE32(close->cl_stateid.si_generation);
- WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
- }
+ if (!nfserr)
+ nfsd4_encode_stateid(resp, &close->cl_stateid);
+
ENCODE_SEQID_OP_TAIL(close->cl_stateowner);
return nfserr;
}
@@ -2074,12 +2094,9 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo
{
ENCODE_SEQID_OP_HEAD;
- if (!nfserr) {
- RESERVE_SPACE(4 + sizeof(stateid_t));
- WRITE32(lock->lk_resp_stateid.si_generation);
- WRITEMEM(&lock->lk_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
- } else if (nfserr == nfserr_denied)
+ if (!nfserr)
+ nfsd4_encode_stateid(resp, &lock->lk_resp_stateid);
+ else if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lock->lk_denied);
ENCODE_SEQID_OP_TAIL(lock->lk_replay_owner);
@@ -2099,13 +2116,9 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l
{
ENCODE_SEQID_OP_HEAD;
- if (!nfserr) {
- RESERVE_SPACE(sizeof(stateid_t));
- WRITE32(locku->lu_stateid.si_generation);
- WRITEMEM(&locku->lu_stateid.si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
- }
-
+ if (!nfserr)
+ nfsd4_encode_stateid(resp, &locku->lu_stateid);
+
ENCODE_SEQID_OP_TAIL(locku->lu_stateowner);
return nfserr;
}
@@ -2128,14 +2141,14 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li
static __be32
nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
{
+ ENCODE_HEAD;
ENCODE_SEQID_OP_HEAD;
if (nfserr)
goto out;
- RESERVE_SPACE(36 + sizeof(stateid_t));
- WRITE32(open->op_stateid.si_generation);
- WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
+ nfsd4_encode_stateid(resp, &open->op_stateid);
+ RESERVE_SPACE(40);
WRITECINFO(open->op_cinfo);
WRITE32(open->op_rflags);
WRITE32(2);
@@ -2148,8 +2161,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
case NFS4_OPEN_DELEGATE_NONE:
break;
case NFS4_OPEN_DELEGATE_READ:
- RESERVE_SPACE(20 + sizeof(stateid_t));
- WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+ nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+ RESERVE_SPACE(20);
WRITE32(open->op_recall);
/*
@@ -2162,8 +2175,8 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op
ADJUST_ARGS();
break;
case NFS4_OPEN_DELEGATE_WRITE:
- RESERVE_SPACE(32 + sizeof(stateid_t));
- WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
+ nfsd4_encode_stateid(resp, &open->op_delegate_stateid);
+ RESERVE_SPACE(32);
WRITE32(0);
/*
@@ -2195,13 +2208,9 @@ static __be32
nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
{
ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr) {
- RESERVE_SPACE(sizeof(stateid_t));
- WRITE32(oc->oc_resp_stateid.si_generation);
- WRITEMEM(&oc->oc_resp_stateid.si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
- }
+
+ if (!nfserr)
+ nfsd4_encode_stateid(resp, &oc->oc_resp_stateid);
ENCODE_SEQID_OP_TAIL(oc->oc_stateowner);
return nfserr;
@@ -2211,13 +2220,9 @@ static __be32
nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
{
ENCODE_SEQID_OP_HEAD;
-
- if (!nfserr) {
- RESERVE_SPACE(sizeof(stateid_t));
- WRITE32(od->od_stateid.si_generation);
- WRITEMEM(&od->od_stateid.si_opaque, sizeof(stateid_opaque_t));
- ADJUST_ARGS();
- }
+
+ if (!nfserr)
+ nfsd4_encode_stateid(resp, &od->od_stateid);
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
return nfserr;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index c53e65f8f3a..97543df5824 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -614,10 +614,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)
return -EINVAL;
err = nfsd_create_serv();
if (!err) {
- int proto = 0;
- err = svc_addsock(nfsd_serv, fd, buf, &proto);
+ err = svc_addsock(nfsd_serv, fd, buf);
if (err >= 0) {
- err = lockd_up(proto);
+ err = lockd_up();
if (err < 0)
svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
}
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index ea37c96f044..cd25d91895a 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -302,17 +302,27 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
if (error)
goto out;
- if (!(access & NFSD_MAY_LOCK)) {
- /*
- * pseudoflavor restrictions are not enforced on NLM,
- * which clients virtually always use auth_sys for,
- * even while using RPCSEC_GSS for NFS.
- */
- error = check_nfsd_access(exp, rqstp);
- if (error)
- goto out;
- }
+ /*
+ * pseudoflavor restrictions are not enforced on NLM,
+ * which clients virtually always use auth_sys for,
+ * even while using RPCSEC_GSS for NFS.
+ */
+ if (access & NFSD_MAY_LOCK)
+ goto skip_pseudoflavor_check;
+ /*
+ * Clients may expect to be able to use auth_sys during mount,
+ * even if they use gss for everything else; see section 2.3.2
+ * of rfc 2623.
+ */
+ if (access & NFSD_MAY_BYPASS_GSS_ON_ROOT
+ && exp->ex_path.dentry == dentry)
+ goto skip_pseudoflavor_check;
+
+ error = check_nfsd_access(exp, rqstp);
+ if (error)
+ goto out;
+skip_pseudoflavor_check:
/* Finally, check access permissions. */
error = nfsd_permission(rqstp, exp, dentry, access);
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 0766f95d236..5cffeca7ace 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -65,7 +65,8 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
- nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
+ nfserr = fh_verify(rqstp, &resp->fh, 0,
+ NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
return nfsd_return_attrs(nfserr, resp);
}
@@ -521,7 +522,8 @@ nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
- nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
+ nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
+ NFSD_MAY_BYPASS_GSS_ON_ROOT);
fh_put(&argp->fh);
return nfserr;
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 80292ff5e92..59eeb46f82c 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -229,6 +229,7 @@ int nfsd_create_serv(void)
atomic_set(&nfsd_busy, 0);
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
+ AF_INET,
nfsd_last_thread, nfsd, THIS_MODULE);
if (nfsd_serv == NULL)
err = -ENOMEM;
@@ -243,25 +244,20 @@ static int nfsd_init_socks(int port)
if (!list_empty(&nfsd_serv->sv_permsocks))
return 0;
- error = lockd_up(IPPROTO_UDP);
- if (error >= 0) {
- error = svc_create_xprt(nfsd_serv, "udp", port,
+ error = svc_create_xprt(nfsd_serv, "udp", port,
SVC_SOCK_DEFAULTS);
- if (error < 0)
- lockd_down();
- }
if (error < 0)
return error;
- error = lockd_up(IPPROTO_TCP);
- if (error >= 0) {
- error = svc_create_xprt(nfsd_serv, "tcp", port,
+ error = svc_create_xprt(nfsd_serv, "tcp", port,
SVC_SOCK_DEFAULTS);
- if (error < 0)
- lockd_down();
- }
if (error < 0)
return error;
+
+ error = lockd_up();
+ if (error < 0)
+ return error;
+
return 0;
}
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 18060bed526..aa1d0d6489a 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -83,7 +83,6 @@ struct raparm_hbucket {
spinlock_t pb_lock;
} ____cacheline_aligned_in_smp;
-static struct raparms * raparml;
#define RAPARM_HASH_BITS 4
#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
@@ -1866,9 +1865,9 @@ out:
* N.B. After this call fhp needs an fh_put
*/
__be32
-nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
+nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access)
{
- __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
+ __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access);
if (!err && vfs_statfs(fhp->fh_dentry,stat))
err = nfserr_io;
return err;
@@ -1966,11 +1965,20 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
void
nfsd_racache_shutdown(void)
{
- if (!raparml)
- return;
+ struct raparms *raparm, *last_raparm;
+ unsigned int i;
+
dprintk("nfsd: freeing readahead buffers.\n");
- kfree(raparml);
- raparml = NULL;
+
+ for (i = 0; i < RAPARM_HASH_SIZE; i++) {
+ raparm = raparm_hash[i].pb_head;
+ while(raparm) {
+ last_raparm = raparm;
+ raparm = raparm->p_next;
+ kfree(last_raparm);
+ }
+ raparm_hash[i].pb_head = NULL;
+ }
}
/*
* Initialize readahead param cache
@@ -1981,35 +1989,38 @@ nfsd_racache_init(int cache_size)
int i;
int j = 0;
int nperbucket;
+ struct raparms **raparm = NULL;
- if (raparml)
+ if (raparm_hash[0].pb_head)
return 0;
- if (cache_size < 2*RAPARM_HASH_SIZE)
- cache_size = 2*RAPARM_HASH_SIZE;
- raparml = kcalloc(cache_size, sizeof(struct raparms), GFP_KERNEL);
-
- if (!raparml) {
- printk(KERN_WARNING
- "nfsd: Could not allocate memory read-ahead cache.\n");
- return -ENOMEM;
- }
+ nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
+ if (nperbucket < 2)
+ nperbucket = 2;
+ cache_size = nperbucket * RAPARM_HASH_SIZE;
dprintk("nfsd: allocating %d readahead buffers.\n", cache_size);
- for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
- raparm_hash[i].pb_head = NULL;
+
+ for (i = 0; i < RAPARM_HASH_SIZE; i++) {
spin_lock_init(&raparm_hash[i].pb_lock);
- }
- nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
- for (i = 0; i < cache_size - 1; i++) {
- if (i % nperbucket == 0)
- raparm_hash[j++].pb_head = raparml + i;
- if (i % nperbucket < nperbucket-1)
- raparml[i].p_next = raparml + i + 1;
+
+ raparm = &raparm_hash[i].pb_head;
+ for (j = 0; j < nperbucket; j++) {
+ *raparm = kzalloc(sizeof(struct raparms), GFP_KERNEL);
+ if (!*raparm)
+ goto out_nomem;
+ raparm = &(*raparm)->p_next;
+ }
+ *raparm = NULL;
}
nfsdstats.ra_size = cache_size;
return 0;
+
+out_nomem:
+ dprintk("nfsd: kmalloc failed, freeing readahead buffers\n");
+ nfsd_racache_shutdown();
+ return -ENOMEM;
}
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
diff --git a/fs/ocfs2/Makefile b/fs/ocfs2/Makefile
index f6956de56fd..589dcdfdfe3 100644
--- a/fs/ocfs2/Makefile
+++ b/fs/ocfs2/Makefile
@@ -34,7 +34,8 @@ ocfs2-objs := \
symlink.o \
sysfile.o \
uptodate.o \
- ver.o
+ ver.o \
+ xattr.o
ocfs2_stackglue-objs := stackglue.o
ocfs2_stack_o2cb-objs := stack_o2cb.o
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
index 29ff57ec5d1..0cc2deb9394 100644
--- a/fs/ocfs2/alloc.c
+++ b/fs/ocfs2/alloc.c
@@ -49,6 +49,340 @@
#include "buffer_head_io.h"
+
+/*
+ * Operations for a specific extent tree type.
+ *
+ * To implement an on-disk btree (extent tree) type in ocfs2, add
+ * an ocfs2_extent_tree_operations structure and the matching
+ * ocfs2_init_<thingy>_extent_tree() function. That's pretty much it
+ * for the allocation portion of the extent tree.
+ */
+struct ocfs2_extent_tree_operations {
+ /*
+ * last_eb_blk is the block number of the right most leaf extent
+ * block. Most on-disk structures containing an extent tree store
+ * this value for fast access. The ->eo_set_last_eb_blk() and
+ * ->eo_get_last_eb_blk() operations access this value. They are
+ * both required.
+ */
+ void (*eo_set_last_eb_blk)(struct ocfs2_extent_tree *et,
+ u64 blkno);
+ u64 (*eo_get_last_eb_blk)(struct ocfs2_extent_tree *et);
+
+ /*
+ * The on-disk structure usually keeps track of how many total
+ * clusters are stored in this extent tree. This function updates
+ * that value. new_clusters is the delta, and must be
+ * added to the total. Required.
+ */
+ void (*eo_update_clusters)(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 new_clusters);
+
+ /*
+ * If ->eo_insert_check() exists, it is called before rec is
+ * inserted into the extent tree. It is optional.
+ */
+ int (*eo_insert_check)(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ struct ocfs2_extent_rec *rec);
+ int (*eo_sanity_check)(struct inode *inode, struct ocfs2_extent_tree *et);
+
+ /*
+ * --------------------------------------------------------------
+ * The remaining are internal to ocfs2_extent_tree and don't have
+ * accessor functions
+ */
+
+ /*
+ * ->eo_fill_root_el() takes et->et_object and sets et->et_root_el.
+ * It is required.
+ */
+ void (*eo_fill_root_el)(struct ocfs2_extent_tree *et);
+
+ /*
+ * ->eo_fill_max_leaf_clusters sets et->et_max_leaf_clusters if
+ * it exists. If it does not, et->et_max_leaf_clusters is set
+ * to 0 (unlimited). Optional.
+ */
+ void (*eo_fill_max_leaf_clusters)(struct inode *inode,
+ struct ocfs2_extent_tree *et);
+};
+
+
+/*
+ * Pre-declare ocfs2_dinode_et_ops so we can use it as a sanity check
+ * in the methods.
+ */
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+ u64 blkno);
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters);
+static int ocfs2_dinode_insert_check(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ struct ocfs2_extent_rec *rec);
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+ struct ocfs2_extent_tree *et);
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et);
+static struct ocfs2_extent_tree_operations ocfs2_dinode_et_ops = {
+ .eo_set_last_eb_blk = ocfs2_dinode_set_last_eb_blk,
+ .eo_get_last_eb_blk = ocfs2_dinode_get_last_eb_blk,
+ .eo_update_clusters = ocfs2_dinode_update_clusters,
+ .eo_insert_check = ocfs2_dinode_insert_check,
+ .eo_sanity_check = ocfs2_dinode_sanity_check,
+ .eo_fill_root_el = ocfs2_dinode_fill_root_el,
+};
+
+static void ocfs2_dinode_set_last_eb_blk(struct ocfs2_extent_tree *et,
+ u64 blkno)
+{
+ struct ocfs2_dinode *di = et->et_object;
+
+ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+ di->i_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_dinode_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_dinode *di = et->et_object;
+
+ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+ return le64_to_cpu(di->i_last_eb_blk);
+}
+
+static void ocfs2_dinode_update_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters)
+{
+ struct ocfs2_dinode *di = et->et_object;
+
+ le32_add_cpu(&di->i_clusters, clusters);
+ spin_lock(&OCFS2_I(inode)->ip_lock);
+ OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
+ spin_unlock(&OCFS2_I(inode)->ip_lock);
+}
+
+static int ocfs2_dinode_insert_check(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ struct ocfs2_extent_rec *rec)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
+ mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
+ (OCFS2_I(inode)->ip_clusters != rec->e_cpos),
+ "Device %s, asking for sparse allocation: inode %llu, "
+ "cpos %u, clusters %u\n",
+ osb->dev_str,
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ rec->e_cpos,
+ OCFS2_I(inode)->ip_clusters);
+
+ return 0;
+}
+
+static int ocfs2_dinode_sanity_check(struct inode *inode,
+ struct ocfs2_extent_tree *et)
+{
+ int ret = 0;
+ struct ocfs2_dinode *di;
+
+ BUG_ON(et->et_ops != &ocfs2_dinode_et_ops);
+
+ di = et->et_object;
+ if (!OCFS2_IS_VALID_DINODE(di)) {
+ ret = -EIO;
+ ocfs2_error(inode->i_sb,
+ "Inode %llu has invalid path root",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ }
+
+ return ret;
+}
+
+static void ocfs2_dinode_fill_root_el(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_dinode *di = et->et_object;
+
+ et->et_root_el = &di->id2.i_list;
+}
+
+
+static void ocfs2_xattr_value_fill_root_el(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_xattr_value_root *xv = et->et_object;
+
+ et->et_root_el = &xv->xr_list;
+}
+
+static void ocfs2_xattr_value_set_last_eb_blk(struct ocfs2_extent_tree *et,
+ u64 blkno)
+{
+ struct ocfs2_xattr_value_root *xv =
+ (struct ocfs2_xattr_value_root *)et->et_object;
+
+ xv->xr_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_value_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_xattr_value_root *xv =
+ (struct ocfs2_xattr_value_root *) et->et_object;
+
+ return le64_to_cpu(xv->xr_last_eb_blk);
+}
+
+static void ocfs2_xattr_value_update_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters)
+{
+ struct ocfs2_xattr_value_root *xv =
+ (struct ocfs2_xattr_value_root *)et->et_object;
+
+ le32_add_cpu(&xv->xr_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_value_et_ops = {
+ .eo_set_last_eb_blk = ocfs2_xattr_value_set_last_eb_blk,
+ .eo_get_last_eb_blk = ocfs2_xattr_value_get_last_eb_blk,
+ .eo_update_clusters = ocfs2_xattr_value_update_clusters,
+ .eo_fill_root_el = ocfs2_xattr_value_fill_root_el,
+};
+
+static void ocfs2_xattr_tree_fill_root_el(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_xattr_block *xb = et->et_object;
+
+ et->et_root_el = &xb->xb_attrs.xb_root.xt_list;
+}
+
+static void ocfs2_xattr_tree_fill_max_leaf_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et)
+{
+ et->et_max_leaf_clusters =
+ ocfs2_clusters_for_bytes(inode->i_sb,
+ OCFS2_MAX_XATTR_TREE_LEAF_SIZE);
+}
+
+static void ocfs2_xattr_tree_set_last_eb_blk(struct ocfs2_extent_tree *et,
+ u64 blkno)
+{
+ struct ocfs2_xattr_block *xb = et->et_object;
+ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+ xt->xt_last_eb_blk = cpu_to_le64(blkno);
+}
+
+static u64 ocfs2_xattr_tree_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+ struct ocfs2_xattr_block *xb = et->et_object;
+ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+
+ return le64_to_cpu(xt->xt_last_eb_blk);
+}
+
+static void ocfs2_xattr_tree_update_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters)
+{
+ struct ocfs2_xattr_block *xb = et->et_object;
+
+ le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, clusters);
+}
+
+static struct ocfs2_extent_tree_operations ocfs2_xattr_tree_et_ops = {
+ .eo_set_last_eb_blk = ocfs2_xattr_tree_set_last_eb_blk,
+ .eo_get_last_eb_blk = ocfs2_xattr_tree_get_last_eb_blk,
+ .eo_update_clusters = ocfs2_xattr_tree_update_clusters,
+ .eo_fill_root_el = ocfs2_xattr_tree_fill_root_el,
+ .eo_fill_max_leaf_clusters = ocfs2_xattr_tree_fill_max_leaf_clusters,
+};
+
+static void __ocfs2_init_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh,
+ void *obj,
+ struct ocfs2_extent_tree_operations *ops)
+{
+ et->et_ops = ops;
+ et->et_root_bh = bh;
+ if (!obj)
+ obj = (void *)bh->b_data;
+ et->et_object = obj;
+
+ et->et_ops->eo_fill_root_el(et);
+ if (!et->et_ops->eo_fill_max_leaf_clusters)
+ et->et_max_leaf_clusters = 0;
+ else
+ et->et_ops->eo_fill_max_leaf_clusters(inode, et);
+}
+
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh)
+{
+ __ocfs2_init_extent_tree(et, inode, bh, NULL, &ocfs2_dinode_et_ops);
+}
+
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh)
+{
+ __ocfs2_init_extent_tree(et, inode, bh, NULL,
+ &ocfs2_xattr_tree_et_ops);
+}
+
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh,
+ struct ocfs2_xattr_value_root *xv)
+{
+ __ocfs2_init_extent_tree(et, inode, bh, xv,
+ &ocfs2_xattr_value_et_ops);
+}
+
+static inline void ocfs2_et_set_last_eb_blk(struct ocfs2_extent_tree *et,
+ u64 new_last_eb_blk)
+{
+ et->et_ops->eo_set_last_eb_blk(et, new_last_eb_blk);
+}
+
+static inline u64 ocfs2_et_get_last_eb_blk(struct ocfs2_extent_tree *et)
+{
+ return et->et_ops->eo_get_last_eb_blk(et);
+}
+
+static inline void ocfs2_et_update_clusters(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters)
+{
+ et->et_ops->eo_update_clusters(inode, et, clusters);
+}
+
+static inline int ocfs2_et_insert_check(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ struct ocfs2_extent_rec *rec)
+{
+ int ret = 0;
+
+ if (et->et_ops->eo_insert_check)
+ ret = et->et_ops->eo_insert_check(inode, et, rec);
+ return ret;
+}
+
+static inline int ocfs2_et_sanity_check(struct inode *inode,
+ struct ocfs2_extent_tree *et)
+{
+ int ret = 0;
+
+ if (et->et_ops->eo_sanity_check)
+ ret = et->et_ops->eo_sanity_check(inode, et);
+ return ret;
+}
+
static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
struct ocfs2_extent_block *eb);
@@ -205,17 +539,6 @@ static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh,
}
/*
- * Allocate and initialize a new path based on a disk inode tree.
- */
-static struct ocfs2_path *ocfs2_new_inode_path(struct buffer_head *di_bh)
-{
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
- struct ocfs2_extent_list *el = &di->id2.i_list;
-
- return ocfs2_new_path(di_bh, el);
-}
-
-/*
* Convenience function to journal all components in a path.
*/
static int ocfs2_journal_access_path(struct inode *inode, handle_t *handle,
@@ -368,39 +691,35 @@ struct ocfs2_merge_ctxt {
*/
int ocfs2_num_free_extents(struct ocfs2_super *osb,
struct inode *inode,
- struct ocfs2_dinode *fe)
+ struct ocfs2_extent_tree *et)
{
int retval;
- struct ocfs2_extent_list *el;
+ struct ocfs2_extent_list *el = NULL;
struct ocfs2_extent_block *eb;
struct buffer_head *eb_bh = NULL;
+ u64 last_eb_blk = 0;
mlog_entry_void();
- if (!OCFS2_IS_VALID_DINODE(fe)) {
- OCFS2_RO_ON_INVALID_DINODE(inode->i_sb, fe);
- retval = -EIO;
- goto bail;
- }
+ el = et->et_root_el;
+ last_eb_blk = ocfs2_et_get_last_eb_blk(et);
- if (fe->i_last_eb_blk) {
- retval = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
- &eb_bh, OCFS2_BH_CACHED, inode);
+ if (last_eb_blk) {
+ retval = ocfs2_read_block(inode, last_eb_blk,
+ &eb_bh);
if (retval < 0) {
mlog_errno(retval);
goto bail;
}
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
- } else
- el = &fe->id2.i_list;
+ }
BUG_ON(el->l_tree_depth != 0);
retval = le16_to_cpu(el->l_count) - le16_to_cpu(el->l_next_free_rec);
bail:
- if (eb_bh)
- brelse(eb_bh);
+ brelse(eb_bh);
mlog_exit(retval);
return retval;
@@ -486,8 +805,7 @@ static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb,
bail:
if (status < 0) {
for(i = 0; i < wanted; i++) {
- if (bhs[i])
- brelse(bhs[i]);
+ brelse(bhs[i]);
bhs[i] = NULL;
}
}
@@ -531,7 +849,7 @@ static inline u32 ocfs2_sum_rightmost_rec(struct ocfs2_extent_list *el)
static int ocfs2_add_branch(struct ocfs2_super *osb,
handle_t *handle,
struct inode *inode,
- struct buffer_head *fe_bh,
+ struct ocfs2_extent_tree *et,
struct buffer_head *eb_bh,
struct buffer_head **last_eb_bh,
struct ocfs2_alloc_context *meta_ac)
@@ -540,7 +858,6 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
u64 next_blkno, new_last_eb_blk;
struct buffer_head *bh;
struct buffer_head **new_eb_bhs = NULL;
- struct ocfs2_dinode *fe;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *eb_el;
struct ocfs2_extent_list *el;
@@ -550,13 +867,11 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
BUG_ON(!last_eb_bh || !*last_eb_bh);
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
-
if (eb_bh) {
eb = (struct ocfs2_extent_block *) eb_bh->b_data;
el = &eb->h_list;
} else
- el = &fe->id2.i_list;
+ el = et->et_root_el;
/* we never add a branch to a leaf. */
BUG_ON(!el->l_tree_depth);
@@ -646,7 +961,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
mlog_errno(status);
goto bail;
}
- status = ocfs2_journal_access(handle, inode, fe_bh,
+ status = ocfs2_journal_access(handle, inode, et->et_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
@@ -662,7 +977,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
}
/* Link the new branch into the rest of the tree (el will
- * either be on the fe, or the extent block passed in. */
+ * either be on the root_bh, or the extent block passed in. */
i = le16_to_cpu(el->l_next_free_rec);
el->l_recs[i].e_blkno = cpu_to_le64(next_blkno);
el->l_recs[i].e_cpos = cpu_to_le32(new_cpos);
@@ -671,7 +986,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
/* fe needs a new last extent block pointer, as does the
* next_leaf on the previously last-extent-block. */
- fe->i_last_eb_blk = cpu_to_le64(new_last_eb_blk);
+ ocfs2_et_set_last_eb_blk(et, new_last_eb_blk);
eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
@@ -679,7 +994,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
status = ocfs2_journal_dirty(handle, *last_eb_bh);
if (status < 0)
mlog_errno(status);
- status = ocfs2_journal_dirty(handle, fe_bh);
+ status = ocfs2_journal_dirty(handle, et->et_root_bh);
if (status < 0)
mlog_errno(status);
if (eb_bh) {
@@ -700,8 +1015,7 @@ static int ocfs2_add_branch(struct ocfs2_super *osb,
bail:
if (new_eb_bhs) {
for (i = 0; i < new_blocks; i++)
- if (new_eb_bhs[i])
- brelse(new_eb_bhs[i]);
+ brelse(new_eb_bhs[i]);
kfree(new_eb_bhs);
}
@@ -717,16 +1031,15 @@ bail:
static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
handle_t *handle,
struct inode *inode,
- struct buffer_head *fe_bh,
+ struct ocfs2_extent_tree *et,
struct ocfs2_alloc_context *meta_ac,
struct buffer_head **ret_new_eb_bh)
{
int status, i;
u32 new_clusters;
struct buffer_head *new_eb_bh = NULL;
- struct ocfs2_dinode *fe;
struct ocfs2_extent_block *eb;
- struct ocfs2_extent_list *fe_el;
+ struct ocfs2_extent_list *root_el;
struct ocfs2_extent_list *eb_el;
mlog_entry_void();
@@ -746,8 +1059,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
}
eb_el = &eb->h_list;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- fe_el = &fe->id2.i_list;
+ root_el = et->et_root_el;
status = ocfs2_journal_access(handle, inode, new_eb_bh,
OCFS2_JOURNAL_ACCESS_CREATE);
@@ -756,11 +1068,11 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
goto bail;
}
- /* copy the fe data into the new extent block */
- eb_el->l_tree_depth = fe_el->l_tree_depth;
- eb_el->l_next_free_rec = fe_el->l_next_free_rec;
- for(i = 0; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
- eb_el->l_recs[i] = fe_el->l_recs[i];
+ /* copy the root extent list data into the new extent block */
+ eb_el->l_tree_depth = root_el->l_tree_depth;
+ eb_el->l_next_free_rec = root_el->l_next_free_rec;
+ for (i = 0; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+ eb_el->l_recs[i] = root_el->l_recs[i];
status = ocfs2_journal_dirty(handle, new_eb_bh);
if (status < 0) {
@@ -768,7 +1080,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
goto bail;
}
- status = ocfs2_journal_access(handle, inode, fe_bh,
+ status = ocfs2_journal_access(handle, inode, et->et_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (status < 0) {
mlog_errno(status);
@@ -777,21 +1089,21 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
new_clusters = ocfs2_sum_rightmost_rec(eb_el);
- /* update fe now */
- le16_add_cpu(&fe_el->l_tree_depth, 1);
- fe_el->l_recs[0].e_cpos = 0;
- fe_el->l_recs[0].e_blkno = eb->h_blkno;
- fe_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
- for(i = 1; i < le16_to_cpu(fe_el->l_next_free_rec); i++)
- memset(&fe_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
- fe_el->l_next_free_rec = cpu_to_le16(1);
+ /* update root_bh now */
+ le16_add_cpu(&root_el->l_tree_depth, 1);
+ root_el->l_recs[0].e_cpos = 0;
+ root_el->l_recs[0].e_blkno = eb->h_blkno;
+ root_el->l_recs[0].e_int_clusters = cpu_to_le32(new_clusters);
+ for (i = 1; i < le16_to_cpu(root_el->l_next_free_rec); i++)
+ memset(&root_el->l_recs[i], 0, sizeof(struct ocfs2_extent_rec));
+ root_el->l_next_free_rec = cpu_to_le16(1);
/* If this is our 1st tree depth shift, then last_eb_blk
* becomes the allocated extent block */
- if (fe_el->l_tree_depth == cpu_to_le16(1))
- fe->i_last_eb_blk = eb->h_blkno;
+ if (root_el->l_tree_depth == cpu_to_le16(1))
+ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
- status = ocfs2_journal_dirty(handle, fe_bh);
+ status = ocfs2_journal_dirty(handle, et->et_root_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -801,8 +1113,7 @@ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb,
new_eb_bh = NULL;
status = 0;
bail:
- if (new_eb_bh)
- brelse(new_eb_bh);
+ brelse(new_eb_bh);
mlog_exit(status);
return status;
@@ -817,22 +1128,21 @@ bail:
* 1) a lowest extent block is found, then we pass it back in
* *lowest_eb_bh and return '0'
*
- * 2) the search fails to find anything, but the dinode has room. We
+ * 2) the search fails to find anything, but the root_el has room. We
* pass NULL back in *lowest_eb_bh, but still return '0'
*
- * 3) the search fails to find anything AND the dinode is full, in
+ * 3) the search fails to find anything AND the root_el is full, in
* which case we return > 0
*
* return status < 0 indicates an error.
*/
static int ocfs2_find_branch_target(struct ocfs2_super *osb,
struct inode *inode,
- struct buffer_head *fe_bh,
+ struct ocfs2_extent_tree *et,
struct buffer_head **target_bh)
{
int status = 0, i;
u64 blkno;
- struct ocfs2_dinode *fe;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el;
struct buffer_head *bh = NULL;
@@ -842,8 +1152,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
*target_bh = NULL;
- fe = (struct ocfs2_dinode *) fe_bh->b_data;
- el = &fe->id2.i_list;
+ el = et->et_root_el;
while(le16_to_cpu(el->l_tree_depth) > 1) {
if (le16_to_cpu(el->l_next_free_rec) == 0) {
@@ -864,13 +1173,10 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
goto bail;
}
- if (bh) {
- brelse(bh);
- bh = NULL;
- }
+ brelse(bh);
+ bh = NULL;
- status = ocfs2_read_block(osb, blkno, &bh, OCFS2_BH_CACHED,
- inode);
+ status = ocfs2_read_block(inode, blkno, &bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -886,8 +1192,7 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
if (le16_to_cpu(el->l_next_free_rec) <
le16_to_cpu(el->l_count)) {
- if (lowest_bh)
- brelse(lowest_bh);
+ brelse(lowest_bh);
lowest_bh = bh;
get_bh(lowest_bh);
}
@@ -895,14 +1200,13 @@ static int ocfs2_find_branch_target(struct ocfs2_super *osb,
/* If we didn't find one and the fe doesn't have any room,
* then return '1' */
- if (!lowest_bh
- && (fe->id2.i_list.l_next_free_rec == fe->id2.i_list.l_count))
+ el = et->et_root_el;
+ if (!lowest_bh && (el->l_next_free_rec == el->l_count))
status = 1;
*target_bh = lowest_bh;
bail:
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
@@ -919,19 +1223,19 @@ bail:
* *last_eb_bh will be updated by ocfs2_add_branch().
*/
static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
- struct buffer_head *di_bh, int *final_depth,
+ struct ocfs2_extent_tree *et, int *final_depth,
struct buffer_head **last_eb_bh,
struct ocfs2_alloc_context *meta_ac)
{
int ret, shift;
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
- int depth = le16_to_cpu(di->id2.i_list.l_tree_depth);
+ struct ocfs2_extent_list *el = et->et_root_el;
+ int depth = le16_to_cpu(el->l_tree_depth);
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
struct buffer_head *bh = NULL;
BUG_ON(meta_ac == NULL);
- shift = ocfs2_find_branch_target(osb, inode, di_bh, &bh);
+ shift = ocfs2_find_branch_target(osb, inode, et, &bh);
if (shift < 0) {
ret = shift;
mlog_errno(ret);
@@ -948,7 +1252,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
/* ocfs2_shift_tree_depth will return us a buffer with
* the new extent block (so we can pass that to
* ocfs2_add_branch). */
- ret = ocfs2_shift_tree_depth(osb, handle, inode, di_bh,
+ ret = ocfs2_shift_tree_depth(osb, handle, inode, et,
meta_ac, &bh);
if (ret < 0) {
mlog_errno(ret);
@@ -975,7 +1279,7 @@ static int ocfs2_grow_tree(struct inode *inode, handle_t *handle,
/* call ocfs2_add_branch to add the final part of the tree with
* the new data. */
mlog(0, "add branch. bh = %p\n", bh);
- ret = ocfs2_add_branch(osb, handle, inode, di_bh, bh, last_eb_bh,
+ ret = ocfs2_add_branch(osb, handle, inode, et, bh, last_eb_bh,
meta_ac);
if (ret < 0) {
mlog_errno(ret);
@@ -1236,8 +1540,7 @@ static int __ocfs2_find_path(struct inode *inode,
brelse(bh);
bh = NULL;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), blkno,
- &bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, blkno, &bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -2058,11 +2361,11 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
struct ocfs2_path *right_path,
int subtree_index,
struct ocfs2_cached_dealloc_ctxt *dealloc,
- int *deleted)
+ int *deleted,
+ struct ocfs2_extent_tree *et)
{
int ret, i, del_right_subtree = 0, right_has_empty = 0;
- struct buffer_head *root_bh, *di_bh = path_root_bh(right_path);
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct buffer_head *root_bh, *et_root_bh = path_root_bh(right_path);
struct ocfs2_extent_list *right_leaf_el, *left_leaf_el;
struct ocfs2_extent_block *eb;
@@ -2114,7 +2417,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
* We have to update i_last_eb_blk during the meta
* data delete.
*/
- ret = ocfs2_journal_access(handle, inode, di_bh,
+ ret = ocfs2_journal_access(handle, inode, et_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
@@ -2189,7 +2492,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
ocfs2_update_edge_lengths(inode, handle, left_path);
eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
- di->i_last_eb_blk = eb->h_blkno;
+ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
/*
* Removal of the extent in the left leaf was skipped
@@ -2199,7 +2502,7 @@ static int ocfs2_rotate_subtree_left(struct inode *inode, handle_t *handle,
if (right_has_empty)
ocfs2_remove_empty_extent(left_leaf_el);
- ret = ocfs2_journal_dirty(handle, di_bh);
+ ret = ocfs2_journal_dirty(handle, et_root_bh);
if (ret)
mlog_errno(ret);
@@ -2322,7 +2625,8 @@ static int __ocfs2_rotate_tree_left(struct inode *inode,
handle_t *handle, int orig_credits,
struct ocfs2_path *path,
struct ocfs2_cached_dealloc_ctxt *dealloc,
- struct ocfs2_path **empty_extent_path)
+ struct ocfs2_path **empty_extent_path,
+ struct ocfs2_extent_tree *et)
{
int ret, subtree_root, deleted;
u32 right_cpos;
@@ -2395,7 +2699,7 @@ static int __ocfs2_rotate_tree_left(struct inode *inode,
ret = ocfs2_rotate_subtree_left(inode, handle, left_path,
right_path, subtree_root,
- dealloc, &deleted);
+ dealloc, &deleted, et);
if (ret == -EAGAIN) {
/*
* The rotation has to temporarily stop due to
@@ -2438,29 +2742,20 @@ out:
}
static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
- struct ocfs2_path *path,
- struct ocfs2_cached_dealloc_ctxt *dealloc)
+ struct ocfs2_path *path,
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_extent_tree *et)
{
int ret, subtree_index;
u32 cpos;
struct ocfs2_path *left_path = NULL;
- struct ocfs2_dinode *di;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el;
- /*
- * XXX: This code assumes that the root is an inode, which is
- * true for now but may change as tree code gets generic.
- */
- di = (struct ocfs2_dinode *)path_root_bh(path)->b_data;
- if (!OCFS2_IS_VALID_DINODE(di)) {
- ret = -EIO;
- ocfs2_error(inode->i_sb,
- "Inode %llu has invalid path root",
- (unsigned long long)OCFS2_I(inode)->ip_blkno);
- goto out;
- }
+ ret = ocfs2_et_sanity_check(inode, et);
+ if (ret)
+ goto out;
/*
* There's two ways we handle this depending on
* whether path is the only existing one.
@@ -2517,7 +2812,7 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
ocfs2_update_edge_lengths(inode, handle, left_path);
eb = (struct ocfs2_extent_block *)path_leaf_bh(left_path)->b_data;
- di->i_last_eb_blk = eb->h_blkno;
+ ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
} else {
/*
* 'path' is also the leftmost path which
@@ -2528,12 +2823,12 @@ static int ocfs2_remove_rightmost_path(struct inode *inode, handle_t *handle,
*/
ocfs2_unlink_path(inode, handle, dealloc, path, 1);
- el = &di->id2.i_list;
+ el = et->et_root_el;
el->l_tree_depth = 0;
el->l_next_free_rec = 0;
memset(&el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
- di->i_last_eb_blk = 0;
+ ocfs2_et_set_last_eb_blk(et, 0);
}
ocfs2_journal_dirty(handle, path_root_bh(path));
@@ -2561,7 +2856,8 @@ out:
*/
static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
struct ocfs2_path *path,
- struct ocfs2_cached_dealloc_ctxt *dealloc)
+ struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_extent_tree *et)
{
int ret, orig_credits = handle->h_buffer_credits;
struct ocfs2_path *tmp_path = NULL, *restart_path = NULL;
@@ -2575,7 +2871,7 @@ static int ocfs2_rotate_tree_left(struct inode *inode, handle_t *handle,
if (path->p_tree_depth == 0) {
rightmost_no_delete:
/*
- * In-inode extents. This is trivially handled, so do
+ * Inline extents. This is trivially handled, so do
* it up front.
*/
ret = ocfs2_rotate_rightmost_leaf_left(inode, handle,
@@ -2629,7 +2925,7 @@ rightmost_no_delete:
*/
ret = ocfs2_remove_rightmost_path(inode, handle, path,
- dealloc);
+ dealloc, et);
if (ret)
mlog_errno(ret);
goto out;
@@ -2641,7 +2937,7 @@ rightmost_no_delete:
*/
try_rotate:
ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits, path,
- dealloc, &restart_path);
+ dealloc, &restart_path, et);
if (ret && ret != -EAGAIN) {
mlog_errno(ret);
goto out;
@@ -2653,7 +2949,7 @@ try_rotate:
ret = __ocfs2_rotate_tree_left(inode, handle, orig_credits,
tmp_path, dealloc,
- &restart_path);
+ &restart_path, et);
if (ret && ret != -EAGAIN) {
mlog_errno(ret);
goto out;
@@ -2939,6 +3235,7 @@ static int ocfs2_merge_rec_left(struct inode *inode,
handle_t *handle,
struct ocfs2_extent_rec *split_rec,
struct ocfs2_cached_dealloc_ctxt *dealloc,
+ struct ocfs2_extent_tree *et,
int index)
{
int ret, i, subtree_index = 0, has_empty_extent = 0;
@@ -3059,7 +3356,8 @@ static int ocfs2_merge_rec_left(struct inode *inode,
le16_to_cpu(el->l_next_free_rec) == 1) {
ret = ocfs2_remove_rightmost_path(inode, handle,
- right_path, dealloc);
+ right_path,
+ dealloc, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -3086,7 +3384,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
int split_index,
struct ocfs2_extent_rec *split_rec,
struct ocfs2_cached_dealloc_ctxt *dealloc,
- struct ocfs2_merge_ctxt *ctxt)
+ struct ocfs2_merge_ctxt *ctxt,
+ struct ocfs2_extent_tree *et)
{
int ret = 0;
@@ -3104,7 +3403,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
* illegal.
*/
ret = ocfs2_rotate_tree_left(inode, handle, path,
- dealloc);
+ dealloc, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -3147,7 +3446,8 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
BUG_ON(!ocfs2_is_empty_extent(&el->l_recs[0]));
/* The merge left us with an empty extent, remove it. */
- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+ ret = ocfs2_rotate_tree_left(inode, handle, path,
+ dealloc, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -3161,7 +3461,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
*/
ret = ocfs2_merge_rec_left(inode, path,
handle, rec,
- dealloc,
+ dealloc, et,
split_index);
if (ret) {
@@ -3170,7 +3470,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
}
ret = ocfs2_rotate_tree_left(inode, handle, path,
- dealloc);
+ dealloc, et);
/*
* Error from this last rotate is not critical, so
* print but don't bubble it up.
@@ -3190,7 +3490,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
ret = ocfs2_merge_rec_left(inode,
path,
handle, split_rec,
- dealloc,
+ dealloc, et,
split_index);
if (ret) {
mlog_errno(ret);
@@ -3213,7 +3513,7 @@ static int ocfs2_try_to_merge_extent(struct inode *inode,
* our leaf. Try to rotate it away.
*/
ret = ocfs2_rotate_tree_left(inode, handle, path,
- dealloc);
+ dealloc, et);
if (ret)
mlog_errno(ret);
ret = 0;
@@ -3347,16 +3647,6 @@ rotate:
ocfs2_rotate_leaf(el, insert_rec);
}
-static inline void ocfs2_update_dinode_clusters(struct inode *inode,
- struct ocfs2_dinode *di,
- u32 clusters)
-{
- le32_add_cpu(&di->i_clusters, clusters);
- spin_lock(&OCFS2_I(inode)->ip_lock);
- OCFS2_I(inode)->ip_clusters = le32_to_cpu(di->i_clusters);
- spin_unlock(&OCFS2_I(inode)->ip_lock);
-}
-
static void ocfs2_adjust_rightmost_records(struct inode *inode,
handle_t *handle,
struct ocfs2_path *path,
@@ -3558,8 +3848,8 @@ static void ocfs2_split_record(struct inode *inode,
}
/*
- * This function only does inserts on an allocation b-tree. For dinode
- * lists, ocfs2_insert_at_leaf() is called directly.
+ * This function only does inserts on an allocation b-tree. For tree
+ * depth = 0, ocfs2_insert_at_leaf() is called directly.
*
* right_path is the path we want to do the actual insert
* in. left_path should only be passed in if we need to update that
@@ -3656,7 +3946,7 @@ out:
static int ocfs2_do_insert_extent(struct inode *inode,
handle_t *handle,
- struct buffer_head *di_bh,
+ struct ocfs2_extent_tree *et,
struct ocfs2_extent_rec *insert_rec,
struct ocfs2_insert_type *type)
{
@@ -3664,13 +3954,11 @@ static int ocfs2_do_insert_extent(struct inode *inode,
u32 cpos;
struct ocfs2_path *right_path = NULL;
struct ocfs2_path *left_path = NULL;
- struct ocfs2_dinode *di;
struct ocfs2_extent_list *el;
- di = (struct ocfs2_dinode *) di_bh->b_data;
- el = &di->id2.i_list;
+ el = et->et_root_el;
- ret = ocfs2_journal_access(handle, inode, di_bh,
+ ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
@@ -3682,7 +3970,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,
goto out_update_clusters;
}
- right_path = ocfs2_new_inode_path(di_bh);
+ right_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
if (!right_path) {
ret = -ENOMEM;
mlog_errno(ret);
@@ -3732,7 +4020,7 @@ static int ocfs2_do_insert_extent(struct inode *inode,
* ocfs2_rotate_tree_right() might have extended the
* transaction without re-journaling our tree root.
*/
- ret = ocfs2_journal_access(handle, inode, di_bh,
+ ret = ocfs2_journal_access(handle, inode, et->et_root_bh,
OCFS2_JOURNAL_ACCESS_WRITE);
if (ret) {
mlog_errno(ret);
@@ -3757,10 +4045,10 @@ static int ocfs2_do_insert_extent(struct inode *inode,
out_update_clusters:
if (type->ins_split == SPLIT_NONE)
- ocfs2_update_dinode_clusters(inode, di,
- le16_to_cpu(insert_rec->e_leaf_clusters));
+ ocfs2_et_update_clusters(inode, et,
+ le16_to_cpu(insert_rec->e_leaf_clusters));
- ret = ocfs2_journal_dirty(handle, di_bh);
+ ret = ocfs2_journal_dirty(handle, et->et_root_bh);
if (ret)
mlog_errno(ret);
@@ -3890,7 +4178,8 @@ out:
static void ocfs2_figure_contig_type(struct inode *inode,
struct ocfs2_insert_type *insert,
struct ocfs2_extent_list *el,
- struct ocfs2_extent_rec *insert_rec)
+ struct ocfs2_extent_rec *insert_rec,
+ struct ocfs2_extent_tree *et)
{
int i;
enum ocfs2_contig_type contig_type = CONTIG_NONE;
@@ -3906,6 +4195,21 @@ static void ocfs2_figure_contig_type(struct inode *inode,
}
}
insert->ins_contig = contig_type;
+
+ if (insert->ins_contig != CONTIG_NONE) {
+ struct ocfs2_extent_rec *rec =
+ &el->l_recs[insert->ins_contig_index];
+ unsigned int len = le16_to_cpu(rec->e_leaf_clusters) +
+ le16_to_cpu(insert_rec->e_leaf_clusters);
+
+ /*
+ * Caller might want us to limit the size of extents, don't
+ * calculate contiguousness if we might exceed that limit.
+ */
+ if (et->et_max_leaf_clusters &&
+ (len > et->et_max_leaf_clusters))
+ insert->ins_contig = CONTIG_NONE;
+ }
}
/*
@@ -3914,8 +4218,8 @@ static void ocfs2_figure_contig_type(struct inode *inode,
* ocfs2_figure_appending_type() will figure out whether we'll have to
* insert at the tail of the rightmost leaf.
*
- * This should also work against the dinode list for tree's with 0
- * depth. If we consider the dinode list to be the rightmost leaf node
+ * This should also work against the root extent list for tree's with 0
+ * depth. If we consider the root extent list to be the rightmost leaf node
* then the logic here makes sense.
*/
static void ocfs2_figure_appending_type(struct ocfs2_insert_type *insert,
@@ -3966,14 +4270,13 @@ set_tail_append:
* structure.
*/
static int ocfs2_figure_insert_type(struct inode *inode,
- struct buffer_head *di_bh,
+ struct ocfs2_extent_tree *et,
struct buffer_head **last_eb_bh,
struct ocfs2_extent_rec *insert_rec,
int *free_records,
struct ocfs2_insert_type *insert)
{
int ret;
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el;
struct ocfs2_path *path = NULL;
@@ -3981,7 +4284,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
insert->ins_split = SPLIT_NONE;
- el = &di->id2.i_list;
+ el = et->et_root_el;
insert->ins_tree_depth = le16_to_cpu(el->l_tree_depth);
if (el->l_tree_depth) {
@@ -3991,9 +4294,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
* ocfs2_figure_insert_type() and ocfs2_add_branch()
* may want it later.
*/
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- le64_to_cpu(di->i_last_eb_blk), &bh,
- OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et), &bh);
if (ret) {
mlog_exit(ret);
goto out;
@@ -4014,12 +4315,12 @@ static int ocfs2_figure_insert_type(struct inode *inode,
le16_to_cpu(el->l_next_free_rec);
if (!insert->ins_tree_depth) {
- ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+ ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
ocfs2_figure_appending_type(insert, el, insert_rec);
return 0;
}
- path = ocfs2_new_inode_path(di_bh);
+ path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
if (!path) {
ret = -ENOMEM;
mlog_errno(ret);
@@ -4048,7 +4349,7 @@ static int ocfs2_figure_insert_type(struct inode *inode,
* into two types of appends: simple record append, or a
* rotate inside the tail leaf.
*/
- ocfs2_figure_contig_type(inode, insert, el, insert_rec);
+ ocfs2_figure_contig_type(inode, insert, el, insert_rec, et);
/*
* The insert code isn't quite ready to deal with all cases of
@@ -4069,7 +4370,8 @@ static int ocfs2_figure_insert_type(struct inode *inode,
* the case that we're doing a tail append, so maybe we can
* take advantage of that information somehow.
*/
- if (le64_to_cpu(di->i_last_eb_blk) == path_leaf_bh(path)->b_blocknr) {
+ if (ocfs2_et_get_last_eb_blk(et) ==
+ path_leaf_bh(path)->b_blocknr) {
/*
* Ok, ocfs2_find_path() returned us the rightmost
* tree path. This might be an appending insert. There are
@@ -4099,7 +4401,7 @@ out:
int ocfs2_insert_extent(struct ocfs2_super *osb,
handle_t *handle,
struct inode *inode,
- struct buffer_head *fe_bh,
+ struct ocfs2_extent_tree *et,
u32 cpos,
u64 start_blk,
u32 new_clusters,
@@ -4112,26 +4414,21 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
struct ocfs2_insert_type insert = {0, };
struct ocfs2_extent_rec rec;
- BUG_ON(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL);
-
mlog(0, "add %u clusters at position %u to inode %llu\n",
new_clusters, cpos, (unsigned long long)OCFS2_I(inode)->ip_blkno);
- mlog_bug_on_msg(!ocfs2_sparse_alloc(osb) &&
- (OCFS2_I(inode)->ip_clusters != cpos),
- "Device %s, asking for sparse allocation: inode %llu, "
- "cpos %u, clusters %u\n",
- osb->dev_str,
- (unsigned long long)OCFS2_I(inode)->ip_blkno, cpos,
- OCFS2_I(inode)->ip_clusters);
-
memset(&rec, 0, sizeof(rec));
rec.e_cpos = cpu_to_le32(cpos);
rec.e_blkno = cpu_to_le64(start_blk);
rec.e_leaf_clusters = cpu_to_le16(new_clusters);
rec.e_flags = flags;
+ status = ocfs2_et_insert_check(inode, et, &rec);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }
- status = ocfs2_figure_insert_type(inode, fe_bh, &last_eb_bh, &rec,
+ status = ocfs2_figure_insert_type(inode, et, &last_eb_bh, &rec,
&free_records, &insert);
if (status < 0) {
mlog_errno(status);
@@ -4145,7 +4442,7 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
free_records, insert.ins_tree_depth);
if (insert.ins_contig == CONTIG_NONE && free_records == 0) {
- status = ocfs2_grow_tree(inode, handle, fe_bh,
+ status = ocfs2_grow_tree(inode, handle, et,
&insert.ins_tree_depth, &last_eb_bh,
meta_ac);
if (status) {
@@ -4155,17 +4452,124 @@ int ocfs2_insert_extent(struct ocfs2_super *osb,
}
/* Finally, we can add clusters. This might rotate the tree for us. */
- status = ocfs2_do_insert_extent(inode, handle, fe_bh, &rec, &insert);
+ status = ocfs2_do_insert_extent(inode, handle, et, &rec, &insert);
if (status < 0)
mlog_errno(status);
- else
+ else if (et->et_ops == &ocfs2_dinode_et_ops)
ocfs2_extent_map_insert_rec(inode, &rec);
bail:
- if (last_eb_bh)
- brelse(last_eb_bh);
+ brelse(last_eb_bh);
+
+ mlog_exit(status);
+ return status;
+}
+
+/*
+ * Allcate and add clusters into the extent b-tree.
+ * The new clusters(clusters_to_add) will be inserted at logical_offset.
+ * The extent b-tree's root is specified by et, and
+ * it is not limited to the file storage. Any extent tree can use this
+ * function if it implements the proper ocfs2_extent_tree.
+ */
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+ struct inode *inode,
+ u32 *logical_offset,
+ u32 clusters_to_add,
+ int mark_unwritten,
+ struct ocfs2_extent_tree *et,
+ handle_t *handle,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ enum ocfs2_alloc_restarted *reason_ret)
+{
+ int status = 0;
+ int free_extents;
+ enum ocfs2_alloc_restarted reason = RESTART_NONE;
+ u32 bit_off, num_bits;
+ u64 block;
+ u8 flags = 0;
+
+ BUG_ON(!clusters_to_add);
+
+ if (mark_unwritten)
+ flags = OCFS2_EXT_UNWRITTEN;
+
+ free_extents = ocfs2_num_free_extents(osb, inode, et);
+ if (free_extents < 0) {
+ status = free_extents;
+ mlog_errno(status);
+ goto leave;
+ }
+
+ /* there are two cases which could cause us to EAGAIN in the
+ * we-need-more-metadata case:
+ * 1) we haven't reserved *any*
+ * 2) we are so fragmented, we've needed to add metadata too
+ * many times. */
+ if (!free_extents && !meta_ac) {
+ mlog(0, "we haven't reserved any metadata!\n");
+ status = -EAGAIN;
+ reason = RESTART_META;
+ goto leave;
+ } else if ((!free_extents)
+ && (ocfs2_alloc_context_bits_left(meta_ac)
+ < ocfs2_extend_meta_needed(et->et_root_el))) {
+ mlog(0, "filesystem is really fragmented...\n");
+ status = -EAGAIN;
+ reason = RESTART_META;
+ goto leave;
+ }
+
+ status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+ clusters_to_add, &bit_off, &num_bits);
+ if (status < 0) {
+ if (status != -ENOSPC)
+ mlog_errno(status);
+ goto leave;
+ }
+
+ BUG_ON(num_bits > clusters_to_add);
+ /* reserve our write early -- insert_extent may update the inode */
+ status = ocfs2_journal_access(handle, inode, et->et_root_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+ mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
+ num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+ status = ocfs2_insert_extent(osb, handle, inode, et,
+ *logical_offset, block,
+ num_bits, flags, meta_ac);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ status = ocfs2_journal_dirty(handle, et->et_root_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ clusters_to_add -= num_bits;
+ *logical_offset += num_bits;
+
+ if (clusters_to_add) {
+ mlog(0, "need to alloc once more, wanted = %u\n",
+ clusters_to_add);
+ status = -EAGAIN;
+ reason = RESTART_TRANS;
+ }
+
+leave:
mlog_exit(status);
+ if (reason_ret)
+ *reason_ret = reason;
return status;
}
@@ -4192,7 +4596,7 @@ static void ocfs2_make_right_split_rec(struct super_block *sb,
static int ocfs2_split_and_insert(struct inode *inode,
handle_t *handle,
struct ocfs2_path *path,
- struct buffer_head *di_bh,
+ struct ocfs2_extent_tree *et,
struct buffer_head **last_eb_bh,
int split_index,
struct ocfs2_extent_rec *orig_split_rec,
@@ -4206,7 +4610,6 @@ static int ocfs2_split_and_insert(struct inode *inode,
struct ocfs2_extent_rec split_rec = *orig_split_rec;
struct ocfs2_insert_type insert;
struct ocfs2_extent_block *eb;
- struct ocfs2_dinode *di;
leftright:
/*
@@ -4215,8 +4618,7 @@ leftright:
*/
rec = path_leaf_el(path)->l_recs[split_index];
- di = (struct ocfs2_dinode *)di_bh->b_data;
- rightmost_el = &di->id2.i_list;
+ rightmost_el = et->et_root_el;
depth = le16_to_cpu(rightmost_el->l_tree_depth);
if (depth) {
@@ -4227,8 +4629,8 @@ leftright:
if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
le16_to_cpu(rightmost_el->l_count)) {
- ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, last_eb_bh,
- meta_ac);
+ ret = ocfs2_grow_tree(inode, handle, et,
+ &depth, last_eb_bh, meta_ac);
if (ret) {
mlog_errno(ret);
goto out;
@@ -4265,8 +4667,7 @@ leftright:
do_leftright = 1;
}
- ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec,
- &insert);
+ ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
if (ret) {
mlog_errno(ret);
goto out;
@@ -4308,8 +4709,9 @@ out:
* of the tree is required. All other cases will degrade into a less
* optimal tree layout.
*
- * last_eb_bh should be the rightmost leaf block for any inode with a
- * btree. Since a split may grow the tree or a merge might shrink it, the caller cannot trust the contents of that buffer after this call.
+ * last_eb_bh should be the rightmost leaf block for any extent
+ * btree. Since a split may grow the tree or a merge might shrink it,
+ * the caller cannot trust the contents of that buffer after this call.
*
* This code is optimized for readability - several passes might be
* made over certain portions of the tree. All of those blocks will
@@ -4317,7 +4719,7 @@ out:
* extra overhead is not expressed in terms of disk reads.
*/
static int __ocfs2_mark_extent_written(struct inode *inode,
- struct buffer_head *di_bh,
+ struct ocfs2_extent_tree *et,
handle_t *handle,
struct ocfs2_path *path,
int split_index,
@@ -4357,11 +4759,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
*/
if (path->p_tree_depth) {
struct ocfs2_extent_block *eb;
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- le64_to_cpu(di->i_last_eb_blk),
- &last_eb_bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+ &last_eb_bh);
if (ret) {
mlog_exit(ret);
goto out;
@@ -4394,7 +4794,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
if (ctxt.c_split_covers_rec)
el->l_recs[split_index] = *split_rec;
else
- ret = ocfs2_split_and_insert(inode, handle, path, di_bh,
+ ret = ocfs2_split_and_insert(inode, handle, path, et,
&last_eb_bh, split_index,
split_rec, meta_ac);
if (ret)
@@ -4402,7 +4802,7 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
} else {
ret = ocfs2_try_to_merge_extent(inode, handle, path,
split_index, split_rec,
- dealloc, &ctxt);
+ dealloc, &ctxt, et);
if (ret)
mlog_errno(ret);
}
@@ -4420,7 +4820,8 @@ out:
*
* The caller is responsible for passing down meta_ac if we'll need it.
*/
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+ struct ocfs2_extent_tree *et,
handle_t *handle, u32 cpos, u32 len, u32 phys,
struct ocfs2_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4446,10 +4847,14 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
/*
* XXX: This should be fixed up so that we just re-insert the
* next extent records.
+ *
+ * XXX: This is a hack on the extent tree, maybe it should be
+ * an op?
*/
- ocfs2_extent_map_trunc(inode, 0);
+ if (et->et_ops == &ocfs2_dinode_et_ops)
+ ocfs2_extent_map_trunc(inode, 0);
- left_path = ocfs2_new_inode_path(di_bh);
+ left_path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
if (!left_path) {
ret = -ENOMEM;
mlog_errno(ret);
@@ -4480,8 +4885,9 @@ int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
split_rec.e_flags = path_leaf_el(left_path)->l_recs[index].e_flags;
split_rec.e_flags &= ~OCFS2_EXT_UNWRITTEN;
- ret = __ocfs2_mark_extent_written(inode, di_bh, handle, left_path,
- index, &split_rec, meta_ac, dealloc);
+ ret = __ocfs2_mark_extent_written(inode, et, handle, left_path,
+ index, &split_rec, meta_ac,
+ dealloc);
if (ret)
mlog_errno(ret);
@@ -4490,13 +4896,12 @@ out:
return ret;
}
-static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
+static int ocfs2_split_tree(struct inode *inode, struct ocfs2_extent_tree *et,
handle_t *handle, struct ocfs2_path *path,
int index, u32 new_range,
struct ocfs2_alloc_context *meta_ac)
{
int ret, depth, credits = handle->h_buffer_credits;
- struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
struct buffer_head *last_eb_bh = NULL;
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *rightmost_el, *el;
@@ -4513,9 +4918,8 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
depth = path->p_tree_depth;
if (depth > 0) {
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- le64_to_cpu(di->i_last_eb_blk),
- &last_eb_bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, ocfs2_et_get_last_eb_blk(et),
+ &last_eb_bh);
if (ret < 0) {
mlog_errno(ret);
goto out;
@@ -4526,7 +4930,8 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
} else
rightmost_el = path_leaf_el(path);
- credits += path->p_tree_depth + ocfs2_extend_meta_needed(di);
+ credits += path->p_tree_depth +
+ ocfs2_extend_meta_needed(et->et_root_el);
ret = ocfs2_extend_trans(handle, credits);
if (ret) {
mlog_errno(ret);
@@ -4535,7 +4940,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
if (le16_to_cpu(rightmost_el->l_next_free_rec) ==
le16_to_cpu(rightmost_el->l_count)) {
- ret = ocfs2_grow_tree(inode, handle, di_bh, &depth, &last_eb_bh,
+ ret = ocfs2_grow_tree(inode, handle, et, &depth, &last_eb_bh,
meta_ac);
if (ret) {
mlog_errno(ret);
@@ -4549,7 +4954,7 @@ static int ocfs2_split_tree(struct inode *inode, struct buffer_head *di_bh,
insert.ins_split = SPLIT_RIGHT;
insert.ins_tree_depth = depth;
- ret = ocfs2_do_insert_extent(inode, handle, di_bh, &split_rec, &insert);
+ ret = ocfs2_do_insert_extent(inode, handle, et, &split_rec, &insert);
if (ret)
mlog_errno(ret);
@@ -4561,7 +4966,8 @@ out:
static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
struct ocfs2_path *path, int index,
struct ocfs2_cached_dealloc_ctxt *dealloc,
- u32 cpos, u32 len)
+ u32 cpos, u32 len,
+ struct ocfs2_extent_tree *et)
{
int ret;
u32 left_cpos, rec_range, trunc_range;
@@ -4573,7 +4979,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
struct ocfs2_extent_block *eb;
if (ocfs2_is_empty_extent(&el->l_recs[0]) && index > 0) {
- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -4704,7 +5110,7 @@ static int ocfs2_truncate_rec(struct inode *inode, handle_t *handle,
ocfs2_journal_dirty(handle, path_leaf_bh(path));
- ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc);
+ ret = ocfs2_rotate_tree_left(inode, handle, path, dealloc, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -4715,7 +5121,8 @@ out:
return ret;
}
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+ struct ocfs2_extent_tree *et,
u32 cpos, u32 len, handle_t *handle,
struct ocfs2_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc)
@@ -4724,11 +5131,11 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
u32 rec_range, trunc_range;
struct ocfs2_extent_rec *rec;
struct ocfs2_extent_list *el;
- struct ocfs2_path *path;
+ struct ocfs2_path *path = NULL;
ocfs2_extent_map_trunc(inode, 0);
- path = ocfs2_new_inode_path(di_bh);
+ path = ocfs2_new_path(et->et_root_bh, et->et_root_el);
if (!path) {
ret = -ENOMEM;
mlog_errno(ret);
@@ -4781,13 +5188,13 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
if (le32_to_cpu(rec->e_cpos) == cpos || rec_range == trunc_range) {
ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
- cpos, len);
+ cpos, len, et);
if (ret) {
mlog_errno(ret);
goto out;
}
} else {
- ret = ocfs2_split_tree(inode, di_bh, handle, path, index,
+ ret = ocfs2_split_tree(inode, et, handle, path, index,
trunc_range, meta_ac);
if (ret) {
mlog_errno(ret);
@@ -4836,7 +5243,7 @@ int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
}
ret = ocfs2_truncate_rec(inode, handle, path, index, dealloc,
- cpos, len);
+ cpos, len, et);
if (ret) {
mlog_errno(ret);
goto out;
@@ -5179,8 +5586,7 @@ static int ocfs2_get_truncate_log_info(struct ocfs2_super *osb,
goto bail;
}
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
- OCFS2_BH_CACHED, inode);
+ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
if (status < 0) {
iput(inode);
mlog_errno(status);
@@ -5255,8 +5661,7 @@ int ocfs2_begin_truncate_log_recovery(struct ocfs2_super *osb,
bail:
if (tl_inode)
iput(tl_inode);
- if (tl_bh)
- brelse(tl_bh);
+ brelse(tl_bh);
if (status < 0 && (*tl_copy)) {
kfree(*tl_copy);
@@ -5999,20 +6404,13 @@ bail:
return status;
}
-static int ocfs2_writeback_zero_func(handle_t *handle, struct buffer_head *bh)
+static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh)
{
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
return 0;
}
-static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
-{
- set_buffer_uptodate(bh);
- mark_buffer_dirty(bh);
- return ocfs2_journal_dirty_data(handle, bh);
-}
-
static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
unsigned int from, unsigned int to,
struct page *page, int zero, u64 *phys)
@@ -6031,17 +6429,18 @@ static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
* here if they aren't - ocfs2_map_page_blocks()
* might've skipped some
*/
- if (ocfs2_should_order_data(inode)) {
- ret = walk_page_buffers(handle,
- page_buffers(page),
- from, to, &partial,
- ocfs2_ordered_zero_func);
- if (ret < 0)
- mlog_errno(ret);
- } else {
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, &partial,
+ ocfs2_zero_func);
+ if (ret < 0)
+ mlog_errno(ret);
+ else if (ocfs2_should_order_data(inode)) {
+ ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
ret = walk_page_buffers(handle, page_buffers(page),
from, to, &partial,
- ocfs2_writeback_zero_func);
+ ocfs2_journal_dirty_data);
+#endif
if (ret < 0)
mlog_errno(ret);
}
@@ -6206,20 +6605,29 @@ out:
return ret;
}
-static void ocfs2_zero_dinode_id2(struct inode *inode, struct ocfs2_dinode *di)
+static void ocfs2_zero_dinode_id2_with_xattr(struct inode *inode,
+ struct ocfs2_dinode *di)
{
unsigned int blocksize = 1 << inode->i_sb->s_blocksize_bits;
+ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
- memset(&di->id2, 0, blocksize - offsetof(struct ocfs2_dinode, id2));
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+ memset(&di->id2, 0, blocksize -
+ offsetof(struct ocfs2_dinode, id2) -
+ xattrsize);
+ else
+ memset(&di->id2, 0, blocksize -
+ offsetof(struct ocfs2_dinode, id2));
}
void ocfs2_dinode_new_extent_list(struct inode *inode,
struct ocfs2_dinode *di)
{
- ocfs2_zero_dinode_id2(inode, di);
+ ocfs2_zero_dinode_id2_with_xattr(inode, di);
di->id2.i_list.l_tree_depth = 0;
di->id2.i_list.l_next_free_rec = 0;
- di->id2.i_list.l_count = cpu_to_le16(ocfs2_extent_recs_per_inode(inode->i_sb));
+ di->id2.i_list.l_count = cpu_to_le16(
+ ocfs2_extent_recs_per_inode_with_xattr(inode->i_sb, di));
}
void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
@@ -6236,9 +6644,10 @@ void ocfs2_set_inode_data_inline(struct inode *inode, struct ocfs2_dinode *di)
* We clear the entire i_data structure here so that all
* fields can be properly initialized.
*/
- ocfs2_zero_dinode_id2(inode, di);
+ ocfs2_zero_dinode_id2_with_xattr(inode, di);
- idata->id_count = cpu_to_le16(ocfs2_max_inline_data(inode->i_sb));
+ idata->id_count = cpu_to_le16(
+ ocfs2_max_inline_data_with_xattr(inode->i_sb, di));
}
int ocfs2_convert_inline_data_to_extents(struct inode *inode,
@@ -6253,6 +6662,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
struct ocfs2_alloc_context *data_ac = NULL;
struct page **pages = NULL;
loff_t end = osb->s_clustersize;
+ struct ocfs2_extent_tree et;
has_data = i_size_read(inode) ? 1 : 0;
@@ -6352,7 +6762,8 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
* this proves to be false, we could always re-build
* the in-inode data from our pages.
*/
- ret = ocfs2_insert_extent(osb, handle, inode, di_bh,
+ ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+ ret = ocfs2_insert_extent(osb, handle, inode, &et,
0, block, 1, 0, NULL);
if (ret) {
mlog_errno(ret);
@@ -6395,13 +6806,14 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
handle_t *handle = NULL;
struct inode *tl_inode = osb->osb_tl_inode;
struct ocfs2_path *path = NULL;
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
mlog_entry_void();
new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
i_size_read(inode));
- path = ocfs2_new_inode_path(fe_bh);
+ path = ocfs2_new_path(fe_bh, &di->id2.i_list);
if (!path) {
status = -ENOMEM;
mlog_errno(status);
@@ -6572,8 +6984,8 @@ int ocfs2_prepare_truncate(struct ocfs2_super *osb,
ocfs2_init_dealloc_ctxt(&(*tc)->tc_dealloc);
if (fe->id2.i_list.l_tree_depth) {
- status = ocfs2_read_block(osb, le64_to_cpu(fe->i_last_eb_blk),
- &last_eb_bh, OCFS2_BH_CACHED, inode);
+ status = ocfs2_read_block(inode, le64_to_cpu(fe->i_last_eb_blk),
+ &last_eb_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -6686,8 +7098,7 @@ static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc)
mlog(ML_NOTICE,
"Truncate completion has non-empty dealloc context\n");
- if (tc->tc_last_eb_bh)
- brelse(tc->tc_last_eb_bh);
+ brelse(tc->tc_last_eb_bh);
kfree(tc);
}
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h
index 60cd3d59230..70257c84cfb 100644
--- a/fs/ocfs2/alloc.h
+++ b/fs/ocfs2/alloc.h
@@ -26,30 +26,102 @@
#ifndef OCFS2_ALLOC_H
#define OCFS2_ALLOC_H
+
+/*
+ * For xattr tree leaf, we limit the leaf byte size to be 64K.
+ */
+#define OCFS2_MAX_XATTR_TREE_LEAF_SIZE 65536
+
+/*
+ * ocfs2_extent_tree and ocfs2_extent_tree_operations are used to abstract
+ * the b-tree operations in ocfs2. Now all the b-tree operations are not
+ * limited to ocfs2_dinode only. Any data which need to allocate clusters
+ * to store can use b-tree. And it only needs to implement its ocfs2_extent_tree
+ * and operation.
+ *
+ * ocfs2_extent_tree becomes the first-class object for extent tree
+ * manipulation. Callers of the alloc.c code need to fill it via one of
+ * the ocfs2_init_*_extent_tree() operations below.
+ *
+ * ocfs2_extent_tree contains info for the root of the b-tree, it must have a
+ * root ocfs2_extent_list and a root_bh so that they can be used in the b-tree
+ * functions.
+ * ocfs2_extent_tree_operations abstract the normal operations we do for
+ * the root of extent b-tree.
+ */
+struct ocfs2_extent_tree_operations;
+struct ocfs2_extent_tree {
+ struct ocfs2_extent_tree_operations *et_ops;
+ struct buffer_head *et_root_bh;
+ struct ocfs2_extent_list *et_root_el;
+ void *et_object;
+ unsigned int et_max_leaf_clusters;
+};
+
+/*
+ * ocfs2_init_*_extent_tree() will fill an ocfs2_extent_tree from the
+ * specified object buffer.
+ */
+void ocfs2_init_dinode_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh);
+void ocfs2_init_xattr_tree_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh);
+void ocfs2_init_xattr_value_extent_tree(struct ocfs2_extent_tree *et,
+ struct inode *inode,
+ struct buffer_head *bh,
+ struct ocfs2_xattr_value_root *xv);
+
struct ocfs2_alloc_context;
int ocfs2_insert_extent(struct ocfs2_super *osb,
handle_t *handle,
struct inode *inode,
- struct buffer_head *fe_bh,
+ struct ocfs2_extent_tree *et,
u32 cpos,
u64 start_blk,
u32 new_clusters,
u8 flags,
struct ocfs2_alloc_context *meta_ac);
+
+enum ocfs2_alloc_restarted {
+ RESTART_NONE = 0,
+ RESTART_TRANS,
+ RESTART_META
+};
+int ocfs2_add_clusters_in_btree(struct ocfs2_super *osb,
+ struct inode *inode,
+ u32 *logical_offset,
+ u32 clusters_to_add,
+ int mark_unwritten,
+ struct ocfs2_extent_tree *et,
+ handle_t *handle,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ enum ocfs2_alloc_restarted *reason_ret);
struct ocfs2_cached_dealloc_ctxt;
-int ocfs2_mark_extent_written(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_mark_extent_written(struct inode *inode,
+ struct ocfs2_extent_tree *et,
handle_t *handle, u32 cpos, u32 len, u32 phys,
struct ocfs2_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc);
-int ocfs2_remove_extent(struct inode *inode, struct buffer_head *di_bh,
+int ocfs2_remove_extent(struct inode *inode,
+ struct ocfs2_extent_tree *et,
u32 cpos, u32 len, handle_t *handle,
struct ocfs2_alloc_context *meta_ac,
struct ocfs2_cached_dealloc_ctxt *dealloc);
int ocfs2_num_free_extents(struct ocfs2_super *osb,
struct inode *inode,
- struct ocfs2_dinode *fe);
-/* how many new metadata chunks would an allocation need at maximum? */
-static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
+ struct ocfs2_extent_tree *et);
+
+/*
+ * how many new metadata chunks would an allocation need at maximum?
+ *
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
+static inline int ocfs2_extend_meta_needed(struct ocfs2_extent_list *root_el)
{
/*
* Rather than do all the work of determining how much we need
@@ -59,7 +131,7 @@ static inline int ocfs2_extend_meta_needed(struct ocfs2_dinode *fe)
* new tree_depth==0 extent_block, and one block at the new
* top-of-the tree.
*/
- return le16_to_cpu(fe->id2.i_list.l_tree_depth) + 2;
+ return le16_to_cpu(root_el->l_tree_depth) + 2;
}
void ocfs2_dinode_new_extent_list(struct inode *inode, struct ocfs2_dinode *di);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index a53da146627..c22543b3342 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -68,9 +68,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
goto bail;
}
- status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- OCFS2_I(inode)->ip_blkno,
- &bh, OCFS2_BH_CACHED, inode);
+ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -128,8 +126,7 @@ static int ocfs2_symlink_get_block(struct inode *inode, sector_t iblock,
err = 0;
bail:
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(err);
return err;
@@ -261,13 +258,11 @@ static int ocfs2_readpage_inline(struct inode *inode, struct page *page)
{
int ret;
struct buffer_head *di_bh = NULL;
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
BUG_ON(!PageLocked(page));
BUG_ON(!(OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL));
- ret = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &di_bh,
- OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -485,11 +480,14 @@ handle_t *ocfs2_start_walk_page_trans(struct inode *inode,
}
if (ocfs2_should_order_data(inode)) {
+ ret = ocfs2_jbd2_file_inode(handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
ret = walk_page_buffers(handle,
page_buffers(page),
from, to, NULL,
ocfs2_journal_dirty_data);
- if (ret < 0)
+#endif
+ if (ret < 0)
mlog_errno(ret);
}
out:
@@ -669,7 +667,7 @@ static void ocfs2_invalidatepage(struct page *page, unsigned long offset)
{
journal_t *journal = OCFS2_SB(page->mapping->host->i_sb)->journal->j_journal;
- journal_invalidatepage(journal, page, offset);
+ jbd2_journal_invalidatepage(journal, page, offset);
}
static int ocfs2_releasepage(struct page *page, gfp_t wait)
@@ -678,7 +676,7 @@ static int ocfs2_releasepage(struct page *page, gfp_t wait)
if (!page_has_buffers(page))
return 0;
- return journal_try_to_free_buffers(journal, page, wait);
+ return jbd2_journal_try_to_free_buffers(journal, page, wait);
}
static ssize_t ocfs2_direct_IO(int rw,
@@ -1074,11 +1072,15 @@ static void ocfs2_write_failure(struct inode *inode,
tmppage = wc->w_pages[i];
if (page_has_buffers(tmppage)) {
- if (ocfs2_should_order_data(inode))
+ if (ocfs2_should_order_data(inode)) {
+ ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
walk_page_buffers(wc->w_handle,
page_buffers(tmppage),
from, to, NULL,
ocfs2_journal_dirty_data);
+#endif
+ }
block_commit_write(tmppage, from, to);
}
@@ -1242,6 +1244,7 @@ static int ocfs2_write_cluster(struct address_space *mapping,
int ret, i, new, should_zero = 0;
u64 v_blkno, p_blkno;
struct inode *inode = mapping->host;
+ struct ocfs2_extent_tree et;
new = phys == 0 ? 1 : 0;
if (new || unwritten)
@@ -1255,10 +1258,10 @@ static int ocfs2_write_cluster(struct address_space *mapping,
* any additional semaphores or cluster locks.
*/
tmp_pos = cpos;
- ret = ocfs2_do_extend_allocation(OCFS2_SB(inode->i_sb), inode,
- &tmp_pos, 1, 0, wc->w_di_bh,
- wc->w_handle, data_ac,
- meta_ac, NULL);
+ ret = ocfs2_add_inode_data(OCFS2_SB(inode->i_sb), inode,
+ &tmp_pos, 1, 0, wc->w_di_bh,
+ wc->w_handle, data_ac,
+ meta_ac, NULL);
/*
* This shouldn't happen because we must have already
* calculated the correct meta data allocation required. The
@@ -1276,7 +1279,8 @@ static int ocfs2_write_cluster(struct address_space *mapping,
goto out;
}
} else if (unwritten) {
- ret = ocfs2_mark_extent_written(inode, wc->w_di_bh,
+ ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+ ret = ocfs2_mark_extent_written(inode, &et,
wc->w_handle, cpos, 1, phys,
meta_ac, &wc->w_dealloc);
if (ret < 0) {
@@ -1665,6 +1669,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
struct ocfs2_alloc_context *data_ac = NULL;
struct ocfs2_alloc_context *meta_ac = NULL;
handle_t *handle;
+ struct ocfs2_extent_tree et;
ret = ocfs2_alloc_write_ctxt(&wc, osb, pos, len, di_bh);
if (ret) {
@@ -1712,14 +1717,23 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
* ocfs2_lock_allocators(). It greatly over-estimates
* the work to be done.
*/
- ret = ocfs2_lock_allocators(inode, di, clusters_to_alloc,
- extents_to_split, &data_ac, &meta_ac);
+ mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u,"
+ " clusters_to_add = %u, extents_to_split = %u\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (long long)i_size_read(inode), le32_to_cpu(di->i_clusters),
+ clusters_to_alloc, extents_to_split);
+
+ ocfs2_init_dinode_extent_tree(&et, inode, wc->w_di_bh);
+ ret = ocfs2_lock_allocators(inode, &et,
+ clusters_to_alloc, extents_to_split,
+ &data_ac, &meta_ac);
if (ret) {
mlog_errno(ret);
goto out;
}
- credits = ocfs2_calc_extend_credits(inode->i_sb, di,
+ credits = ocfs2_calc_extend_credits(inode->i_sb,
+ &di->id2.i_list,
clusters_to_alloc);
}
@@ -1905,11 +1919,15 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
}
if (page_has_buffers(tmppage)) {
- if (ocfs2_should_order_data(inode))
+ if (ocfs2_should_order_data(inode)) {
+ ocfs2_jbd2_file_inode(wc->w_handle, inode);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
walk_page_buffers(wc->w_handle,
page_buffers(tmppage),
from, to, NULL,
ocfs2_journal_dirty_data);
+#endif
+ }
block_commit_write(tmppage, from, to);
}
}
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index f136639f5b4..7e947c67246 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -66,7 +66,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
/* remove from dirty list before I/O. */
clear_buffer_dirty(bh);
- get_bh(bh); /* for end_buffer_write_sync() */
+ get_bh(bh); /* for end_buffer_write_sync() */
bh->b_end_io = end_buffer_write_sync;
submit_bh(WRITE, bh);
@@ -88,22 +88,103 @@ out:
return ret;
}
-int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
- struct buffer_head *bhs[], int flags,
- struct inode *inode)
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+ unsigned int nr, struct buffer_head *bhs[])
+{
+ int status = 0;
+ unsigned int i;
+ struct buffer_head *bh;
+
+ if (!nr) {
+ mlog(ML_BH_IO, "No buffers will be read!\n");
+ goto bail;
+ }
+
+ for (i = 0 ; i < nr ; i++) {
+ if (bhs[i] == NULL) {
+ bhs[i] = sb_getblk(osb->sb, block++);
+ if (bhs[i] == NULL) {
+ status = -EIO;
+ mlog_errno(status);
+ goto bail;
+ }
+ }
+ bh = bhs[i];
+
+ if (buffer_jbd(bh)) {
+ mlog(ML_ERROR,
+ "trying to sync read a jbd "
+ "managed bh (blocknr = %llu), skipping\n",
+ (unsigned long long)bh->b_blocknr);
+ continue;
+ }
+
+ if (buffer_dirty(bh)) {
+ /* This should probably be a BUG, or
+ * at least return an error. */
+ mlog(ML_ERROR,
+ "trying to sync read a dirty "
+ "buffer! (blocknr = %llu), skipping\n",
+ (unsigned long long)bh->b_blocknr);
+ continue;
+ }
+
+ lock_buffer(bh);
+ if (buffer_jbd(bh)) {
+ mlog(ML_ERROR,
+ "block %llu had the JBD bit set "
+ "while I was in lock_buffer!",
+ (unsigned long long)bh->b_blocknr);
+ BUG();
+ }
+
+ clear_buffer_uptodate(bh);
+ get_bh(bh); /* for end_buffer_read_sync() */
+ bh->b_end_io = end_buffer_read_sync;
+ submit_bh(READ, bh);
+ }
+
+ for (i = nr; i > 0; i--) {
+ bh = bhs[i - 1];
+
+ if (buffer_jbd(bh)) {
+ mlog(ML_ERROR,
+ "the journal got the buffer while it was "
+ "locked for io! (blocknr = %llu)\n",
+ (unsigned long long)bh->b_blocknr);
+ BUG();
+ }
+
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ /* Status won't be cleared from here on out,
+ * so we can safely record this and loop back
+ * to cleanup the other buffers. */
+ status = -EIO;
+ put_bh(bh);
+ bhs[i - 1] = NULL;
+ }
+ }
+
+bail:
+ return status;
+}
+
+int ocfs2_read_blocks(struct inode *inode, u64 block, int nr,
+ struct buffer_head *bhs[], int flags)
{
int status = 0;
- struct super_block *sb;
int i, ignore_cache = 0;
struct buffer_head *bh;
- mlog_entry("(block=(%llu), nr=(%d), flags=%d, inode=%p)\n",
- (unsigned long long)block, nr, flags, inode);
+ mlog_entry("(inode=%p, block=(%llu), nr=(%d), flags=%d)\n",
+ inode, (unsigned long long)block, nr, flags);
+ BUG_ON(!inode);
BUG_ON((flags & OCFS2_BH_READAHEAD) &&
- (!inode || !(flags & OCFS2_BH_CACHED)));
+ (flags & OCFS2_BH_IGNORE_CACHE));
- if (osb == NULL || osb->sb == NULL || bhs == NULL) {
+ if (bhs == NULL) {
status = -EINVAL;
mlog_errno(status);
goto bail;
@@ -122,26 +203,19 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
goto bail;
}
- sb = osb->sb;
-
- if (flags & OCFS2_BH_CACHED && !inode)
- flags &= ~OCFS2_BH_CACHED;
-
- if (inode)
- mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
+ mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
for (i = 0 ; i < nr ; i++) {
if (bhs[i] == NULL) {
- bhs[i] = sb_getblk(sb, block++);
+ bhs[i] = sb_getblk(inode->i_sb, block++);
if (bhs[i] == NULL) {
- if (inode)
- mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
status = -EIO;
mlog_errno(status);
goto bail;
}
}
bh = bhs[i];
- ignore_cache = 0;
+ ignore_cache = (flags & OCFS2_BH_IGNORE_CACHE);
/* There are three read-ahead cases here which we need to
* be concerned with. All three assume a buffer has
@@ -167,26 +241,27 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
* before our is-it-in-flight check.
*/
- if (flags & OCFS2_BH_CACHED &&
- !ocfs2_buffer_uptodate(inode, bh)) {
+ if (!ignore_cache && !ocfs2_buffer_uptodate(inode, bh)) {
mlog(ML_UPTODATE,
"bh (%llu), inode %llu not uptodate\n",
(unsigned long long)bh->b_blocknr,
(unsigned long long)OCFS2_I(inode)->ip_blkno);
+ /* We're using ignore_cache here to say
+ * "go to disk" */
ignore_cache = 1;
}
/* XXX: Can we ever get this and *not* have the cached
* flag set? */
if (buffer_jbd(bh)) {
- if (!(flags & OCFS2_BH_CACHED) || ignore_cache)
+ if (ignore_cache)
mlog(ML_BH_IO, "trying to sync read a jbd "
"managed bh (blocknr = %llu)\n",
(unsigned long long)bh->b_blocknr);
continue;
}
- if (!(flags & OCFS2_BH_CACHED) || ignore_cache) {
+ if (ignore_cache) {
if (buffer_dirty(bh)) {
/* This should probably be a BUG, or
* at least return an error. */
@@ -221,7 +296,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
* previously read-ahead buffer may have
* completed I/O while we were waiting for the
* buffer lock. */
- if ((flags & OCFS2_BH_CACHED)
+ if (!(flags & OCFS2_BH_IGNORE_CACHE)
&& !(flags & OCFS2_BH_READAHEAD)
&& ocfs2_buffer_uptodate(inode, bh)) {
unlock_buffer(bh);
@@ -265,15 +340,14 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
/* Always set the buffer in the cache, even if it was
* a forced read, or read-ahead which hasn't yet
* completed. */
- if (inode)
- ocfs2_set_buffer_uptodate(inode, bh);
+ ocfs2_set_buffer_uptodate(inode, bh);
}
- if (inode)
- mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
mlog(ML_BH_IO, "block=(%llu), nr=(%d), cached=%s, flags=0x%x\n",
(unsigned long long)block, nr,
- (!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes", flags);
+ ((flags & OCFS2_BH_IGNORE_CACHE) || ignore_cache) ? "no" : "yes",
+ flags);
bail:
diff --git a/fs/ocfs2/buffer_head_io.h b/fs/ocfs2/buffer_head_io.h
index c2e78614c3e..75e1dcb1ade 100644
--- a/fs/ocfs2/buffer_head_io.h
+++ b/fs/ocfs2/buffer_head_io.h
@@ -31,31 +31,29 @@
void ocfs2_end_buffer_io_sync(struct buffer_head *bh,
int uptodate);
-static inline int ocfs2_read_block(struct ocfs2_super *osb,
+static inline int ocfs2_read_block(struct inode *inode,
u64 off,
- struct buffer_head **bh,
- int flags,
- struct inode *inode);
+ struct buffer_head **bh);
int ocfs2_write_block(struct ocfs2_super *osb,
struct buffer_head *bh,
struct inode *inode);
-int ocfs2_read_blocks(struct ocfs2_super *osb,
+int ocfs2_read_blocks(struct inode *inode,
u64 block,
int nr,
struct buffer_head *bhs[],
- int flags,
- struct inode *inode);
+ int flags);
+int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
+ unsigned int nr, struct buffer_head *bhs[]);
int ocfs2_write_super_or_backup(struct ocfs2_super *osb,
struct buffer_head *bh);
-#define OCFS2_BH_CACHED 1
+#define OCFS2_BH_IGNORE_CACHE 1
#define OCFS2_BH_READAHEAD 8
-static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
- struct buffer_head **bh, int flags,
- struct inode *inode)
+static inline int ocfs2_read_block(struct inode *inode, u64 off,
+ struct buffer_head **bh)
{
int status = 0;
@@ -65,8 +63,7 @@ static inline int ocfs2_read_block(struct ocfs2_super * osb, u64 off,
goto bail;
}
- status = ocfs2_read_blocks(osb, off, 1, bh,
- flags, inode);
+ status = ocfs2_read_blocks(inode, off, 1, bh, 0);
bail:
return status;
diff --git a/fs/ocfs2/cluster/masklog.c b/fs/ocfs2/cluster/masklog.c
index 23c732f2752..d8a0cb92cef 100644
--- a/fs/ocfs2/cluster/masklog.c
+++ b/fs/ocfs2/cluster/masklog.c
@@ -109,6 +109,7 @@ static struct mlog_attribute mlog_attrs[MLOG_MAX_BITS] = {
define_mask(CONN),
define_mask(QUORUM),
define_mask(EXPORT),
+ define_mask(XATTR),
define_mask(ERROR),
define_mask(NOTICE),
define_mask(KTHREAD),
diff --git a/fs/ocfs2/cluster/masklog.h b/fs/ocfs2/cluster/masklog.h
index 597e064bb94..57670c68047 100644
--- a/fs/ocfs2/cluster/masklog.h
+++ b/fs/ocfs2/cluster/masklog.h
@@ -112,6 +112,7 @@
#define ML_CONN 0x0000000004000000ULL /* net connection management */
#define ML_QUORUM 0x0000000008000000ULL /* net connection quorum */
#define ML_EXPORT 0x0000000010000000ULL /* ocfs2 export operations */
+#define ML_XATTR 0x0000000020000000ULL /* ocfs2 extended attributes */
/* bits that are infrequently given and frequently matched in the high word */
#define ML_ERROR 0x0000000100000000ULL /* sent to KERN_ERR */
#define ML_NOTICE 0x0000000200000000ULL /* setn to KERN_NOTICE */
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 9cce563fd62..026e6eb8518 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -82,6 +82,49 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
struct ocfs2_alloc_context *meta_ac,
struct buffer_head **new_bh);
+static struct buffer_head *ocfs2_bread(struct inode *inode,
+ int block, int *err, int reada)
+{
+ struct buffer_head *bh = NULL;
+ int tmperr;
+ u64 p_blkno;
+ int readflags = 0;
+
+ if (reada)
+ readflags |= OCFS2_BH_READAHEAD;
+
+ if (((u64)block << inode->i_sb->s_blocksize_bits) >=
+ i_size_read(inode)) {
+ BUG_ON(!reada);
+ return NULL;
+ }
+
+ down_read(&OCFS2_I(inode)->ip_alloc_sem);
+ tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
+ NULL);
+ up_read(&OCFS2_I(inode)->ip_alloc_sem);
+ if (tmperr < 0) {
+ mlog_errno(tmperr);
+ goto fail;
+ }
+
+ tmperr = ocfs2_read_blocks(inode, p_blkno, 1, &bh, readflags);
+ if (tmperr < 0)
+ goto fail;
+
+ tmperr = 0;
+
+ *err = 0;
+ return bh;
+
+fail:
+ brelse(bh);
+ bh = NULL;
+
+ *err = -EIO;
+ return NULL;
+}
+
/*
* bh passed here can be an inode block or a dir data block, depending
* on the inode inline data flag.
@@ -188,8 +231,7 @@ static struct buffer_head *ocfs2_find_entry_id(const char *name,
struct ocfs2_dinode *di;
struct ocfs2_inline_data *data;
- ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
- &di_bh, OCFS2_BH_CACHED, dir);
+ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -260,14 +302,13 @@ restart:
}
if ((bh = bh_use[ra_ptr++]) == NULL)
goto next;
- wait_on_buffer(bh);
- if (!buffer_uptodate(bh)) {
- /* read error, skip block & hope for the best */
+ if (ocfs2_read_block(dir, block, &bh)) {
+ /* read error, skip block & hope for the best.
+ * ocfs2_read_block() has released the bh. */
ocfs2_error(dir->i_sb, "reading directory %llu, "
"offset %lu\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno,
block);
- brelse(bh);
goto next;
}
i = ocfs2_search_dirblock(bh, dir, name, namelen,
@@ -417,8 +458,7 @@ static inline int ocfs2_delete_entry_id(handle_t *handle,
struct ocfs2_dinode *di;
struct ocfs2_inline_data *data;
- ret = ocfs2_read_block(OCFS2_SB(dir->i_sb), OCFS2_I(dir)->ip_blkno,
- &di_bh, OCFS2_BH_CACHED, dir);
+ ret = ocfs2_read_block(dir, OCFS2_I(dir)->ip_blkno, &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -596,8 +636,7 @@ static int ocfs2_dir_foreach_blk_id(struct inode *inode,
struct ocfs2_inline_data *data;
struct ocfs2_dir_entry *de;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
- &di_bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
if (ret) {
mlog(ML_ERROR, "Unable to read inode block for dir %llu\n",
(unsigned long long)OCFS2_I(inode)->ip_blkno);
@@ -716,8 +755,7 @@ static int ocfs2_dir_foreach_blk_el(struct inode *inode,
for (i = ra_sectors >> (sb->s_blocksize_bits - 9);
i > 0; i--) {
tmp = ocfs2_bread(inode, ++blk, &err, 1);
- if (tmp)
- brelse(tmp);
+ brelse(tmp);
}
last_ra_blk = blk;
ra_sectors = 8;
@@ -899,10 +937,8 @@ int ocfs2_find_files_on_disk(const char *name,
leave:
if (status < 0) {
*dirent = NULL;
- if (*dirent_bh) {
- brelse(*dirent_bh);
- *dirent_bh = NULL;
- }
+ brelse(*dirent_bh);
+ *dirent_bh = NULL;
}
mlog_exit(status);
@@ -951,8 +987,7 @@ int ocfs2_check_dir_for_entry(struct inode *dir,
ret = 0;
bail:
- if (dirent_bh)
- brelse(dirent_bh);
+ brelse(dirent_bh);
mlog_exit(ret);
return ret;
@@ -1127,8 +1162,7 @@ static int ocfs2_fill_new_dir_el(struct ocfs2_super *osb,
status = 0;
bail:
- if (new_bh)
- brelse(new_bh);
+ brelse(new_bh);
mlog_exit(status);
return status;
@@ -1192,6 +1226,9 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
struct buffer_head *dirdata_bh = NULL;
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
handle_t *handle;
+ struct ocfs2_extent_tree et;
+
+ ocfs2_init_dinode_extent_tree(&et, dir, di_bh);
alloc = ocfs2_clusters_for_bytes(sb, bytes);
@@ -1305,8 +1342,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
* This should never fail as our extent list is empty and all
* related blocks have been journaled already.
*/
- ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 0, blkno, len, 0,
- NULL);
+ ret = ocfs2_insert_extent(osb, handle, dir, &et, 0, blkno, len,
+ 0, NULL);
if (ret) {
mlog_errno(ret);
goto out_commit;
@@ -1337,8 +1374,8 @@ static int ocfs2_expand_inline_dir(struct inode *dir, struct buffer_head *di_bh,
}
blkno = ocfs2_clusters_to_blocks(dir->i_sb, bit_off);
- ret = ocfs2_insert_extent(osb, handle, dir, di_bh, 1, blkno,
- len, 0, NULL);
+ ret = ocfs2_insert_extent(osb, handle, dir, &et, 1,
+ blkno, len, 0, NULL);
if (ret) {
mlog_errno(ret);
goto out_commit;
@@ -1383,9 +1420,9 @@ static int ocfs2_do_extend_dir(struct super_block *sb,
if (extend) {
u32 offset = OCFS2_I(dir)->ip_clusters;
- status = ocfs2_do_extend_allocation(OCFS2_SB(sb), dir, &offset,
- 1, 0, parent_fe_bh, handle,
- data_ac, meta_ac, NULL);
+ status = ocfs2_add_inode_data(OCFS2_SB(sb), dir, &offset,
+ 1, 0, parent_fe_bh, handle,
+ data_ac, meta_ac, NULL);
BUG_ON(status == -EAGAIN);
if (status < 0) {
mlog_errno(status);
@@ -1430,12 +1467,14 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
int credits, num_free_extents, drop_alloc_sem = 0;
loff_t dir_i_size;
struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data;
+ struct ocfs2_extent_list *el = &fe->id2.i_list;
struct ocfs2_alloc_context *data_ac = NULL;
struct ocfs2_alloc_context *meta_ac = NULL;
handle_t *handle = NULL;
struct buffer_head *new_bh = NULL;
struct ocfs2_dir_entry * de;
struct super_block *sb = osb->sb;
+ struct ocfs2_extent_tree et;
mlog_entry_void();
@@ -1479,7 +1518,8 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
spin_lock(&OCFS2_I(dir)->ip_lock);
if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) {
spin_unlock(&OCFS2_I(dir)->ip_lock);
- num_free_extents = ocfs2_num_free_extents(osb, dir, fe);
+ ocfs2_init_dinode_extent_tree(&et, dir, parent_fe_bh);
+ num_free_extents = ocfs2_num_free_extents(osb, dir, &et);
if (num_free_extents < 0) {
status = num_free_extents;
mlog_errno(status);
@@ -1487,7 +1527,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
}
if (!num_free_extents) {
- status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac);
+ status = ocfs2_reserve_new_metadata(osb, el, &meta_ac);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -1502,7 +1542,7 @@ static int ocfs2_extend_dir(struct ocfs2_super *osb,
goto bail;
}
- credits = ocfs2_calc_extend_credits(sb, fe, 1);
+ credits = ocfs2_calc_extend_credits(sb, el, 1);
} else {
spin_unlock(&OCFS2_I(dir)->ip_lock);
credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS;
@@ -1568,8 +1608,7 @@ bail:
if (meta_ac)
ocfs2_free_alloc_context(meta_ac);
- if (new_bh)
- brelse(new_bh);
+ brelse(new_bh);
mlog_exit(status);
return status;
@@ -1696,8 +1735,7 @@ static int ocfs2_find_dir_space_el(struct inode *dir, const char *name,
status = 0;
bail:
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
@@ -1756,7 +1794,6 @@ int ocfs2_prepare_dir_for_insert(struct ocfs2_super *osb,
*ret_de_bh = bh;
bh = NULL;
out:
- if (bh)
- brelse(bh);
+ brelse(bh);
return ret;
}
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index eae3d643a5e..ec684426034 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2024,8 +2024,7 @@ static int ocfs2_inode_lock_update(struct inode *inode,
} else {
/* Boo, we have to go to disk. */
/* read bh, cast, ocfs2_refresh_inode */
- status = ocfs2_read_block(OCFS2_SB(inode->i_sb), oi->ip_blkno,
- bh, OCFS2_BH_CACHED, inode);
+ status = ocfs2_read_block(inode, oi->ip_blkno, bh);
if (status < 0) {
mlog_errno(status);
goto bail_refresh;
@@ -2086,11 +2085,7 @@ static int ocfs2_assign_bh(struct inode *inode,
return 0;
}
- status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- OCFS2_I(inode)->ip_blkno,
- ret_bh,
- OCFS2_BH_CACHED,
- inode);
+ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, ret_bh);
if (status < 0)
mlog_errno(status);
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index aed268e80b4..2baedac5823 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -293,8 +293,7 @@ static int ocfs2_last_eb_is_empty(struct inode *inode,
struct ocfs2_extent_block *eb;
struct ocfs2_extent_list *el;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), last_eb_blk,
- &eb_bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, last_eb_blk, &eb_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -382,9 +381,9 @@ static int ocfs2_figure_hole_clusters(struct inode *inode,
if (le64_to_cpu(eb->h_next_leaf_blk) == 0ULL)
goto no_more_extents;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
+ ret = ocfs2_read_block(inode,
le64_to_cpu(eb->h_next_leaf_blk),
- &next_eb_bh, OCFS2_BH_CACHED, inode);
+ &next_eb_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -551,6 +550,66 @@ static void ocfs2_relative_extent_offsets(struct super_block *sb,
*num_clusters = le16_to_cpu(rec->e_leaf_clusters) - coff;
}
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+ u32 *p_cluster, u32 *num_clusters,
+ struct ocfs2_extent_list *el)
+{
+ int ret = 0, i;
+ struct buffer_head *eb_bh = NULL;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_rec *rec;
+ u32 coff;
+
+ if (el->l_tree_depth) {
+ ret = ocfs2_find_leaf(inode, el, v_cluster, &eb_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+ el = &eb->h_list;
+
+ if (el->l_tree_depth) {
+ ocfs2_error(inode->i_sb,
+ "Inode %lu has non zero tree depth in "
+ "xattr leaf block %llu\n", inode->i_ino,
+ (unsigned long long)eb_bh->b_blocknr);
+ ret = -EROFS;
+ goto out;
+ }
+ }
+
+ i = ocfs2_search_extent_list(el, v_cluster);
+ if (i == -1) {
+ ret = -EROFS;
+ mlog_errno(ret);
+ goto out;
+ } else {
+ rec = &el->l_recs[i];
+ BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos));
+
+ if (!rec->e_blkno) {
+ ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+ "record (%u, %u, 0) in xattr", inode->i_ino,
+ le32_to_cpu(rec->e_cpos),
+ ocfs2_rec_clusters(el, rec));
+ ret = -EROFS;
+ goto out;
+ }
+ coff = v_cluster - le32_to_cpu(rec->e_cpos);
+ *p_cluster = ocfs2_blocks_to_clusters(inode->i_sb,
+ le64_to_cpu(rec->e_blkno));
+ *p_cluster = *p_cluster + coff;
+ if (num_clusters)
+ *num_clusters = ocfs2_rec_clusters(el, rec) - coff;
+ }
+out:
+ if (eb_bh)
+ brelse(eb_bh);
+ return ret;
+}
+
int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
u32 *p_cluster, u32 *num_clusters,
unsigned int *extent_flags)
@@ -571,8 +630,7 @@ int ocfs2_get_clusters(struct inode *inode, u32 v_cluster,
if (ret == 0)
goto out;
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb), OCFS2_I(inode)->ip_blkno,
- &di_bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
diff --git a/fs/ocfs2/extent_map.h b/fs/ocfs2/extent_map.h
index 1b97490e1ea..1c4aa8b06f3 100644
--- a/fs/ocfs2/extent_map.h
+++ b/fs/ocfs2/extent_map.h
@@ -53,4 +53,8 @@ int ocfs2_extent_map_get_blocks(struct inode *inode, u64 v_blkno, u64 *p_blkno,
int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
u64 map_start, u64 map_len);
+int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster,
+ u32 *p_cluster, u32 *num_clusters,
+ struct ocfs2_extent_list *el);
+
#endif /* _EXTENT_MAP_H */
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index ed38796052d..8d3225a7807 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -55,6 +55,7 @@
#include "mmap.h"
#include "suballoc.h"
#include "super.h"
+#include "xattr.h"
#include "buffer_head_io.h"
@@ -184,7 +185,7 @@ static int ocfs2_sync_file(struct file *file,
goto bail;
journal = osb->journal->j_journal;
- err = journal_force_commit(journal);
+ err = jbd2_journal_force_commit(journal);
bail:
mlog_exit(err);
@@ -488,7 +489,7 @@ bail:
}
/*
- * extend allocation only here.
+ * extend file allocation only here.
* we'll update all the disk stuff, and oip->alloc_size
*
* expect stuff to be locked, a transaction started and enough data /
@@ -497,189 +498,25 @@ bail:
* Will return -EAGAIN, and a reason if a restart is needed.
* If passed in, *reason will always be set, even in error.
*/
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
- struct inode *inode,
- u32 *logical_offset,
- u32 clusters_to_add,
- int mark_unwritten,
- struct buffer_head *fe_bh,
- handle_t *handle,
- struct ocfs2_alloc_context *data_ac,
- struct ocfs2_alloc_context *meta_ac,
- enum ocfs2_alloc_restarted *reason_ret)
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+ struct inode *inode,
+ u32 *logical_offset,
+ u32 clusters_to_add,
+ int mark_unwritten,
+ struct buffer_head *fe_bh,
+ handle_t *handle,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ enum ocfs2_alloc_restarted *reason_ret)
{
- int status = 0;
- int free_extents;
- struct ocfs2_dinode *fe = (struct ocfs2_dinode *) fe_bh->b_data;
- enum ocfs2_alloc_restarted reason = RESTART_NONE;
- u32 bit_off, num_bits;
- u64 block;
- u8 flags = 0;
-
- BUG_ON(!clusters_to_add);
-
- if (mark_unwritten)
- flags = OCFS2_EXT_UNWRITTEN;
-
- free_extents = ocfs2_num_free_extents(osb, inode, fe);
- if (free_extents < 0) {
- status = free_extents;
- mlog_errno(status);
- goto leave;
- }
-
- /* there are two cases which could cause us to EAGAIN in the
- * we-need-more-metadata case:
- * 1) we haven't reserved *any*
- * 2) we are so fragmented, we've needed to add metadata too
- * many times. */
- if (!free_extents && !meta_ac) {
- mlog(0, "we haven't reserved any metadata!\n");
- status = -EAGAIN;
- reason = RESTART_META;
- goto leave;
- } else if ((!free_extents)
- && (ocfs2_alloc_context_bits_left(meta_ac)
- < ocfs2_extend_meta_needed(fe))) {
- mlog(0, "filesystem is really fragmented...\n");
- status = -EAGAIN;
- reason = RESTART_META;
- goto leave;
- }
-
- status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
- clusters_to_add, &bit_off, &num_bits);
- if (status < 0) {
- if (status != -ENOSPC)
- mlog_errno(status);
- goto leave;
- }
-
- BUG_ON(num_bits > clusters_to_add);
-
- /* reserve our write early -- insert_extent may update the inode */
- status = ocfs2_journal_access(handle, inode, fe_bh,
- OCFS2_JOURNAL_ACCESS_WRITE);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
-
- block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
- mlog(0, "Allocating %u clusters at block %u for inode %llu\n",
- num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
- status = ocfs2_insert_extent(osb, handle, inode, fe_bh,
- *logical_offset, block, num_bits,
- flags, meta_ac);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
-
- status = ocfs2_journal_dirty(handle, fe_bh);
- if (status < 0) {
- mlog_errno(status);
- goto leave;
- }
-
- clusters_to_add -= num_bits;
- *logical_offset += num_bits;
-
- if (clusters_to_add) {
- mlog(0, "need to alloc once more, clusters = %u, wanted = "
- "%u\n", fe->i_clusters, clusters_to_add);
- status = -EAGAIN;
- reason = RESTART_TRANS;
- }
-
-leave:
- mlog_exit(status);
- if (reason_ret)
- *reason_ret = reason;
- return status;
-}
-
-/*
- * For a given allocation, determine which allocators will need to be
- * accessed, and lock them, reserving the appropriate number of bits.
- *
- * Sparse file systems call this from ocfs2_write_begin_nolock()
- * and ocfs2_allocate_unwritten_extents().
- *
- * File systems which don't support holes call this from
- * ocfs2_extend_allocation().
- */
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
- u32 clusters_to_add, u32 extents_to_split,
- struct ocfs2_alloc_context **data_ac,
- struct ocfs2_alloc_context **meta_ac)
-{
- int ret = 0, num_free_extents;
- unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
- *meta_ac = NULL;
- if (data_ac)
- *data_ac = NULL;
-
- BUG_ON(clusters_to_add != 0 && data_ac == NULL);
-
- mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
- "clusters_to_add = %u, extents_to_split = %u\n",
- (unsigned long long)OCFS2_I(inode)->ip_blkno, (long long)i_size_read(inode),
- le32_to_cpu(di->i_clusters), clusters_to_add, extents_to_split);
-
- num_free_extents = ocfs2_num_free_extents(osb, inode, di);
- if (num_free_extents < 0) {
- ret = num_free_extents;
- mlog_errno(ret);
- goto out;
- }
-
- /*
- * Sparse allocation file systems need to be more conservative
- * with reserving room for expansion - the actual allocation
- * happens while we've got a journal handle open so re-taking
- * a cluster lock (because we ran out of room for another
- * extent) will violate ordering rules.
- *
- * Most of the time we'll only be seeing this 1 cluster at a time
- * anyway.
- *
- * Always lock for any unwritten extents - we might want to
- * add blocks during a split.
- */
- if (!num_free_extents ||
- (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
- ret = ocfs2_reserve_new_metadata(osb, di, meta_ac);
- if (ret < 0) {
- if (ret != -ENOSPC)
- mlog_errno(ret);
- goto out;
- }
- }
-
- if (clusters_to_add == 0)
- goto out;
-
- ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
- if (ret < 0) {
- if (ret != -ENOSPC)
- mlog_errno(ret);
- goto out;
- }
-
-out:
- if (ret) {
- if (*meta_ac) {
- ocfs2_free_alloc_context(*meta_ac);
- *meta_ac = NULL;
- }
+ int ret;
+ struct ocfs2_extent_tree et;
- /*
- * We cannot have an error and a non null *data_ac.
- */
- }
+ ocfs2_init_dinode_extent_tree(&et, inode, fe_bh);
+ ret = ocfs2_add_clusters_in_btree(osb, inode, logical_offset,
+ clusters_to_add, mark_unwritten,
+ &et, handle,
+ data_ac, meta_ac, reason_ret);
return ret;
}
@@ -698,6 +535,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
struct ocfs2_alloc_context *meta_ac = NULL;
enum ocfs2_alloc_restarted why;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_extent_tree et;
mlog_entry("(clusters_to_add = %u)\n", clusters_to_add);
@@ -707,8 +545,7 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
*/
BUG_ON(mark_unwritten && !ocfs2_sparse_alloc(osb));
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, &bh,
- OCFS2_BH_CACHED, inode);
+ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, &bh);
if (status < 0) {
mlog_errno(status);
goto leave;
@@ -724,14 +561,21 @@ static int __ocfs2_extend_allocation(struct inode *inode, u32 logical_start,
restart_all:
BUG_ON(le32_to_cpu(fe->i_clusters) != OCFS2_I(inode)->ip_clusters);
- status = ocfs2_lock_allocators(inode, fe, clusters_to_add, 0, &data_ac,
- &meta_ac);
+ mlog(0, "extend inode %llu, i_size = %lld, di->i_clusters = %u, "
+ "clusters_to_add = %u\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ (long long)i_size_read(inode), le32_to_cpu(fe->i_clusters),
+ clusters_to_add);
+ ocfs2_init_dinode_extent_tree(&et, inode, bh);
+ status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+ &data_ac, &meta_ac);
if (status) {
mlog_errno(status);
goto leave;
}
- credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add);
+ credits = ocfs2_calc_extend_credits(osb->sb, &fe->id2.i_list,
+ clusters_to_add);
handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
@@ -753,16 +597,16 @@ restarted_transaction:
prev_clusters = OCFS2_I(inode)->ip_clusters;
- status = ocfs2_do_extend_allocation(osb,
- inode,
- &logical_start,
- clusters_to_add,
- mark_unwritten,
- bh,
- handle,
- data_ac,
- meta_ac,
- &why);
+ status = ocfs2_add_inode_data(osb,
+ inode,
+ &logical_start,
+ clusters_to_add,
+ mark_unwritten,
+ bh,
+ handle,
+ data_ac,
+ meta_ac,
+ &why);
if ((status < 0) && (status != -EAGAIN)) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -789,7 +633,7 @@ restarted_transaction:
mlog(0, "restarting transaction.\n");
/* TODO: This can be more intelligent. */
credits = ocfs2_calc_extend_credits(osb->sb,
- fe,
+ &fe->id2.i_list,
clusters_to_add);
status = ocfs2_extend_trans(handle, credits);
if (status < 0) {
@@ -826,10 +670,8 @@ leave:
restart_func = 0;
goto restart_all;
}
- if (bh) {
- brelse(bh);
- bh = NULL;
- }
+ brelse(bh);
+ bh = NULL;
mlog_exit(status);
return status;
@@ -1096,9 +938,15 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr)
goto bail_unlock;
}
- if (i_size_read(inode) > attr->ia_size)
+ if (i_size_read(inode) > attr->ia_size) {
+ if (ocfs2_should_order_data(inode)) {
+ status = ocfs2_begin_ordered_truncate(inode,
+ attr->ia_size);
+ if (status)
+ goto bail_unlock;
+ }
status = ocfs2_truncate_file(inode, bh, attr->ia_size);
- else
+ } else
status = ocfs2_extend_file(inode, bh, attr->ia_size);
if (status < 0) {
if (status != -ENOSPC)
@@ -1140,8 +988,7 @@ bail_unlock_rw:
if (size_change)
ocfs2_rw_unlock(inode, 1);
bail:
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
@@ -1284,8 +1131,7 @@ static int ocfs2_write_remove_suid(struct inode *inode)
struct buffer_head *bh = NULL;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- oi->ip_blkno, &bh, OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, oi->ip_blkno, &bh);
if (ret < 0) {
mlog_errno(ret);
goto out;
@@ -1311,9 +1157,8 @@ static int ocfs2_allocate_unwritten_extents(struct inode *inode,
struct buffer_head *di_bh = NULL;
if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
- ret = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- OCFS2_I(inode)->ip_blkno, &di_bh,
- OCFS2_BH_CACHED, inode);
+ ret = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno,
+ &di_bh);
if (ret) {
mlog_errno(ret);
goto out;
@@ -1394,8 +1239,11 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
handle_t *handle;
struct ocfs2_alloc_context *meta_ac = NULL;
struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_extent_tree et;
- ret = ocfs2_lock_allocators(inode, di, 0, 1, NULL, &meta_ac);
+ ocfs2_init_dinode_extent_tree(&et, inode, di_bh);
+
+ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
if (ret) {
mlog_errno(ret);
return ret;
@@ -1425,7 +1273,7 @@ static int __ocfs2_remove_inode_range(struct inode *inode,
goto out;
}
- ret = ocfs2_remove_extent(inode, di_bh, cpos, len, handle, meta_ac,
+ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
dealloc);
if (ret) {
mlog_errno(ret);
@@ -2040,7 +1888,7 @@ out_dio:
*/
if (old_size != i_size_read(inode) ||
old_clusters != OCFS2_I(inode)->ip_clusters) {
- ret = journal_force_commit(osb->journal->j_journal);
+ ret = jbd2_journal_force_commit(osb->journal->j_journal);
if (ret < 0)
written = ret;
}
@@ -2227,6 +2075,10 @@ const struct inode_operations ocfs2_file_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ocfs2_listxattr,
+ .removexattr = generic_removexattr,
.fallocate = ocfs2_fallocate,
.fiemap = ocfs2_fiemap,
};
@@ -2237,6 +2089,10 @@ const struct inode_operations ocfs2_special_file_iops = {
.permission = ocfs2_permission,
};
+/*
+ * Other than ->lock, keep ocfs2_fops and ocfs2_dops in sync with
+ * ocfs2_fops_no_plocks and ocfs2_dops_no_plocks!
+ */
const struct file_operations ocfs2_fops = {
.llseek = generic_file_llseek,
.read = do_sync_read,
@@ -2251,6 +2107,7 @@ const struct file_operations ocfs2_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ocfs2_compat_ioctl,
#endif
+ .lock = ocfs2_lock,
.flock = ocfs2_flock,
.splice_read = ocfs2_file_splice_read,
.splice_write = ocfs2_file_splice_write,
@@ -2267,5 +2124,51 @@ const struct file_operations ocfs2_dops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = ocfs2_compat_ioctl,
#endif
+ .lock = ocfs2_lock,
+ .flock = ocfs2_flock,
+};
+
+/*
+ * POSIX-lockless variants of our file_operations.
+ *
+ * These will be used if the underlying cluster stack does not support
+ * posix file locking, if the user passes the "localflocks" mount
+ * option, or if we have a local-only fs.
+ *
+ * ocfs2_flock is in here because all stacks handle UNIX file locks,
+ * so we still want it in the case of no stack support for
+ * plocks. Internally, it will do the right thing when asked to ignore
+ * the cluster.
+ */
+const struct file_operations ocfs2_fops_no_plocks = {
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .mmap = ocfs2_mmap,
+ .fsync = ocfs2_sync_file,
+ .release = ocfs2_file_release,
+ .open = ocfs2_file_open,
+ .aio_read = ocfs2_file_aio_read,
+ .aio_write = ocfs2_file_aio_write,
+ .unlocked_ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ocfs2_compat_ioctl,
+#endif
+ .flock = ocfs2_flock,
+ .splice_read = ocfs2_file_splice_read,
+ .splice_write = ocfs2_file_splice_write,
+};
+
+const struct file_operations ocfs2_dops_no_plocks = {
+ .llseek = generic_file_llseek,
+ .read = generic_read_dir,
+ .readdir = ocfs2_readdir,
+ .fsync = ocfs2_sync_file,
+ .release = ocfs2_dir_release,
+ .open = ocfs2_dir_open,
+ .unlocked_ioctl = ocfs2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ocfs2_compat_ioctl,
+#endif
.flock = ocfs2_flock,
};
diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h
index 1e27b4d017e..e92382cbca5 100644
--- a/fs/ocfs2/file.h
+++ b/fs/ocfs2/file.h
@@ -28,9 +28,12 @@
extern const struct file_operations ocfs2_fops;
extern const struct file_operations ocfs2_dops;
+extern const struct file_operations ocfs2_fops_no_plocks;
+extern const struct file_operations ocfs2_dops_no_plocks;
extern const struct inode_operations ocfs2_file_iops;
extern const struct inode_operations ocfs2_special_file_iops;
struct ocfs2_alloc_context;
+enum ocfs2_alloc_restarted;
struct ocfs2_file_private {
struct file *fp_file;
@@ -38,27 +41,18 @@ struct ocfs2_file_private {
struct ocfs2_lock_res fp_flock;
};
-enum ocfs2_alloc_restarted {
- RESTART_NONE = 0,
- RESTART_TRANS,
- RESTART_META
-};
-int ocfs2_do_extend_allocation(struct ocfs2_super *osb,
- struct inode *inode,
- u32 *logical_offset,
- u32 clusters_to_add,
- int mark_unwritten,
- struct buffer_head *fe_bh,
- handle_t *handle,
- struct ocfs2_alloc_context *data_ac,
- struct ocfs2_alloc_context *meta_ac,
- enum ocfs2_alloc_restarted *reason_ret);
+int ocfs2_add_inode_data(struct ocfs2_super *osb,
+ struct inode *inode,
+ u32 *logical_offset,
+ u32 clusters_to_add,
+ int mark_unwritten,
+ struct buffer_head *fe_bh,
+ handle_t *handle,
+ struct ocfs2_alloc_context *data_ac,
+ struct ocfs2_alloc_context *meta_ac,
+ enum ocfs2_alloc_restarted *reason_ret);
int ocfs2_extend_no_holes(struct inode *inode, u64 new_i_size,
u64 zero_to);
-int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_dinode *di,
- u32 clusters_to_add, u32 extents_to_split,
- struct ocfs2_alloc_context **data_ac,
- struct ocfs2_alloc_context **meta_ac);
int ocfs2_setattr(struct dentry *dentry, struct iattr *attr);
int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct kstat *stat);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 7e9e4c79aec..4903688f72a 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -49,6 +49,7 @@
#include "symlink.h"
#include "sysfile.h"
#include "uptodate.h"
+#include "xattr.h"
#include "buffer_head_io.h"
@@ -219,6 +220,7 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
struct super_block *sb;
struct ocfs2_super *osb;
int status = -EINVAL;
+ int use_plocks = 1;
mlog_entry("(0x%p, size:%llu)\n", inode,
(unsigned long long)le64_to_cpu(fe->i_size));
@@ -226,6 +228,10 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
sb = inode->i_sb;
osb = OCFS2_SB(sb);
+ if ((osb->s_mount_opt & OCFS2_MOUNT_LOCALFLOCKS) ||
+ ocfs2_mount_local(osb) || !ocfs2_stack_supports_plocks())
+ use_plocks = 0;
+
/* this means that read_inode cannot create a superblock inode
* today. change if needed. */
if (!OCFS2_IS_VALID_DINODE(fe) ||
@@ -295,13 +301,19 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
- inode->i_fop = &ocfs2_fops;
+ if (use_plocks)
+ inode->i_fop = &ocfs2_fops;
+ else
+ inode->i_fop = &ocfs2_fops_no_plocks;
inode->i_op = &ocfs2_file_iops;
i_size_write(inode, le64_to_cpu(fe->i_size));
break;
case S_IFDIR:
inode->i_op = &ocfs2_dir_iops;
- inode->i_fop = &ocfs2_dops;
+ if (use_plocks)
+ inode->i_fop = &ocfs2_dops;
+ else
+ inode->i_fop = &ocfs2_dops_no_plocks;
i_size_write(inode, le64_to_cpu(fe->i_size));
break;
case S_IFLNK:
@@ -448,8 +460,11 @@ static int ocfs2_read_locked_inode(struct inode *inode,
}
}
- status = ocfs2_read_block(osb, args->fi_blkno, &bh, 0,
- can_lock ? inode : NULL);
+ if (can_lock)
+ status = ocfs2_read_blocks(inode, args->fi_blkno, 1, &bh,
+ OCFS2_BH_IGNORE_CACHE);
+ else
+ status = ocfs2_read_blocks_sync(osb, args->fi_blkno, 1, &bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -522,6 +537,9 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
* data and fast symlinks.
*/
if (fe->i_clusters) {
+ if (ocfs2_should_order_data(inode))
+ ocfs2_begin_ordered_truncate(inode, 0);
+
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
@@ -730,6 +748,13 @@ static int ocfs2_wipe_inode(struct inode *inode,
goto bail_unlock_dir;
}
+ /*Free extended attribute resources associated with this inode.*/
+ status = ocfs2_xattr_remove(inode, di_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail_unlock_dir;
+ }
+
status = ocfs2_remove_inode(inode, di_bh, orphan_dir_inode,
orphan_dir_bh);
if (status < 0)
@@ -1081,6 +1106,8 @@ void ocfs2_clear_inode(struct inode *inode)
oi->ip_last_trans = 0;
oi->ip_dir_start_lookup = 0;
oi->ip_blkno = 0ULL;
+ jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal,
+ &oi->ip_jinode);
bail:
mlog_exit_void();
@@ -1107,58 +1134,6 @@ void ocfs2_drop_inode(struct inode *inode)
}
/*
- * TODO: this should probably be merged into ocfs2_get_block
- *
- * However, you now need to pay attention to the cont_prepare_write()
- * stuff in ocfs2_get_block (that is, ocfs2_get_block pretty much
- * expects never to extend).
- */
-struct buffer_head *ocfs2_bread(struct inode *inode,
- int block, int *err, int reada)
-{
- struct buffer_head *bh = NULL;
- int tmperr;
- u64 p_blkno;
- int readflags = OCFS2_BH_CACHED;
-
- if (reada)
- readflags |= OCFS2_BH_READAHEAD;
-
- if (((u64)block << inode->i_sb->s_blocksize_bits) >=
- i_size_read(inode)) {
- BUG_ON(!reada);
- return NULL;
- }
-
- down_read(&OCFS2_I(inode)->ip_alloc_sem);
- tmperr = ocfs2_extent_map_get_blocks(inode, block, &p_blkno, NULL,
- NULL);
- up_read(&OCFS2_I(inode)->ip_alloc_sem);
- if (tmperr < 0) {
- mlog_errno(tmperr);
- goto fail;
- }
-
- tmperr = ocfs2_read_block(OCFS2_SB(inode->i_sb), p_blkno, &bh,
- readflags, inode);
- if (tmperr < 0)
- goto fail;
-
- tmperr = 0;
-
- *err = 0;
- return bh;
-
-fail:
- if (bh) {
- brelse(bh);
- bh = NULL;
- }
- *err = -EIO;
- return NULL;
-}
-
-/*
* This is called from our getattr.
*/
int ocfs2_inode_revalidate(struct dentry *dentry)
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 390a85596aa..2f37af9bcc4 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -40,6 +40,9 @@ struct ocfs2_inode_info
/* protects allocation changes on this inode. */
struct rw_semaphore ip_alloc_sem;
+ /* protects extended attribute changes on this inode */
+ struct rw_semaphore ip_xattr_sem;
+
/* These fields are protected by ip_lock */
spinlock_t ip_lock;
u32 ip_open_count;
@@ -68,6 +71,7 @@ struct ocfs2_inode_info
struct ocfs2_extent_map ip_extent_map;
struct inode vfs_inode;
+ struct jbd2_inode ip_jinode;
};
/*
@@ -113,8 +117,6 @@ extern struct kmem_cache *ocfs2_inode_cache;
extern const struct address_space_operations ocfs2_aops;
-struct buffer_head *ocfs2_bread(struct inode *inode, int block,
- int *err, int reada);
void ocfs2_clear_inode(struct inode *inode);
void ocfs2_delete_inode(struct inode *inode);
void ocfs2_drop_inode(struct inode *inode);
diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c
index 7b142f0ce99..9fcd36dcc9a 100644
--- a/fs/ocfs2/ioctl.c
+++ b/fs/ocfs2/ioctl.c
@@ -102,8 +102,7 @@ bail_unlock:
bail:
mutex_unlock(&inode->i_mutex);
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index c47bc2a809c..81e40677eec 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -215,9 +215,9 @@ static int ocfs2_commit_cache(struct ocfs2_super *osb)
goto finally;
}
- journal_lock_updates(journal->j_journal);
- status = journal_flush(journal->j_journal);
- journal_unlock_updates(journal->j_journal);
+ jbd2_journal_lock_updates(journal->j_journal);
+ status = jbd2_journal_flush(journal->j_journal);
+ jbd2_journal_unlock_updates(journal->j_journal);
if (status < 0) {
up_write(&journal->j_trans_barrier);
mlog_errno(status);
@@ -264,7 +264,7 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs)
down_read(&osb->journal->j_trans_barrier);
- handle = journal_start(journal, max_buffs);
+ handle = jbd2_journal_start(journal, max_buffs);
if (IS_ERR(handle)) {
up_read(&osb->journal->j_trans_barrier);
@@ -290,7 +290,7 @@ int ocfs2_commit_trans(struct ocfs2_super *osb,
BUG_ON(!handle);
- ret = journal_stop(handle);
+ ret = jbd2_journal_stop(handle);
if (ret < 0)
mlog_errno(ret);
@@ -304,7 +304,7 @@ int ocfs2_commit_trans(struct ocfs2_super *osb,
* transaction. extend_trans will either extend the current handle by
* nblocks, or commit it and start a new one with nblocks credits.
*
- * This might call journal_restart() which will commit dirty buffers
+ * This might call jbd2_journal_restart() which will commit dirty buffers
* and then restart the transaction. Before calling
* ocfs2_extend_trans(), any changed blocks should have been
* dirtied. After calling it, all blocks which need to be changed must
@@ -332,7 +332,7 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
#ifdef CONFIG_OCFS2_DEBUG_FS
status = 1;
#else
- status = journal_extend(handle, nblocks);
+ status = jbd2_journal_extend(handle, nblocks);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -340,8 +340,10 @@ int ocfs2_extend_trans(handle_t *handle, int nblocks)
#endif
if (status > 0) {
- mlog(0, "journal_extend failed, trying journal_restart\n");
- status = journal_restart(handle, nblocks);
+ mlog(0,
+ "jbd2_journal_extend failed, trying "
+ "jbd2_journal_restart\n");
+ status = jbd2_journal_restart(handle, nblocks);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -393,11 +395,11 @@ int ocfs2_journal_access(handle_t *handle,
switch (type) {
case OCFS2_JOURNAL_ACCESS_CREATE:
case OCFS2_JOURNAL_ACCESS_WRITE:
- status = journal_get_write_access(handle, bh);
+ status = jbd2_journal_get_write_access(handle, bh);
break;
case OCFS2_JOURNAL_ACCESS_UNDO:
- status = journal_get_undo_access(handle, bh);
+ status = jbd2_journal_get_undo_access(handle, bh);
break;
default:
@@ -422,7 +424,7 @@ int ocfs2_journal_dirty(handle_t *handle,
mlog_entry("(bh->b_blocknr=%llu)\n",
(unsigned long long)bh->b_blocknr);
- status = journal_dirty_metadata(handle, bh);
+ status = jbd2_journal_dirty_metadata(handle, bh);
if (status < 0)
mlog(ML_ERROR, "Could not dirty metadata buffer. "
"(bh->b_blocknr=%llu)\n",
@@ -432,6 +434,7 @@ int ocfs2_journal_dirty(handle_t *handle,
return status;
}
+#ifdef CONFIG_OCFS2_COMPAT_JBD
int ocfs2_journal_dirty_data(handle_t *handle,
struct buffer_head *bh)
{
@@ -443,8 +446,9 @@ int ocfs2_journal_dirty_data(handle_t *handle,
return err;
}
+#endif
-#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * JBD_DEFAULT_MAX_COMMIT_AGE)
+#define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE)
void ocfs2_set_journal_params(struct ocfs2_super *osb)
{
@@ -457,9 +461,9 @@ void ocfs2_set_journal_params(struct ocfs2_super *osb)
spin_lock(&journal->j_state_lock);
journal->j_commit_interval = commit_interval;
if (osb->s_mount_opt & OCFS2_MOUNT_BARRIER)
- journal->j_flags |= JFS_BARRIER;
+ journal->j_flags |= JBD2_BARRIER;
else
- journal->j_flags &= ~JFS_BARRIER;
+ journal->j_flags &= ~JBD2_BARRIER;
spin_unlock(&journal->j_state_lock);
}
@@ -524,14 +528,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
mlog(0, "inode->ip_clusters = %u\n", OCFS2_I(inode)->ip_clusters);
/* call the kernels journal init function now */
- j_journal = journal_init_inode(inode);
+ j_journal = jbd2_journal_init_inode(inode);
if (j_journal == NULL) {
mlog(ML_ERROR, "Linux journal layer error\n");
status = -EINVAL;
goto done;
}
- mlog(0, "Returned from journal_init_inode\n");
+ mlog(0, "Returned from jbd2_journal_init_inode\n");
mlog(0, "j_journal->j_maxlen = %u\n", j_journal->j_maxlen);
*dirty = (le32_to_cpu(di->id1.journal1.ij_flags) &
@@ -550,8 +554,7 @@ done:
if (status < 0) {
if (inode_lock)
ocfs2_inode_unlock(inode, 1);
- if (bh != NULL)
- brelse(bh);
+ brelse(bh);
if (inode) {
OCFS2_I(inode)->ip_open_count--;
iput(inode);
@@ -639,7 +642,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
if (journal->j_state != OCFS2_JOURNAL_LOADED)
goto done;
- /* need to inc inode use count as journal_destroy will iput. */
+ /* need to inc inode use count - jbd2_journal_destroy will iput. */
if (!igrab(inode))
BUG();
@@ -668,9 +671,9 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
BUG_ON(atomic_read(&(osb->journal->j_num_trans)) != 0);
if (ocfs2_mount_local(osb)) {
- journal_lock_updates(journal->j_journal);
- status = journal_flush(journal->j_journal);
- journal_unlock_updates(journal->j_journal);
+ jbd2_journal_lock_updates(journal->j_journal);
+ status = jbd2_journal_flush(journal->j_journal);
+ jbd2_journal_unlock_updates(journal->j_journal);
if (status < 0)
mlog_errno(status);
}
@@ -686,7 +689,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
}
/* Shutdown the kernel journal system */
- journal_destroy(journal->j_journal);
+ jbd2_journal_destroy(journal->j_journal);
OCFS2_I(inode)->ip_open_count--;
@@ -711,15 +714,15 @@ static void ocfs2_clear_journal_error(struct super_block *sb,
{
int olderr;
- olderr = journal_errno(journal);
+ olderr = jbd2_journal_errno(journal);
if (olderr) {
mlog(ML_ERROR, "File system error %d recorded in "
"journal %u.\n", olderr, slot);
mlog(ML_ERROR, "File system on device %s needs checking.\n",
sb->s_id);
- journal_ack_err(journal);
- journal_clear_err(journal);
+ jbd2_journal_ack_err(journal);
+ jbd2_journal_clear_err(journal);
}
}
@@ -734,7 +737,7 @@ int ocfs2_journal_load(struct ocfs2_journal *journal, int local, int replayed)
osb = journal->j_osb;
- status = journal_load(journal->j_journal);
+ status = jbd2_journal_load(journal->j_journal);
if (status < 0) {
mlog(ML_ERROR, "Failed to load journal!\n");
goto done;
@@ -778,7 +781,7 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full)
BUG_ON(!journal);
- status = journal_wipe(journal->j_journal, full);
+ status = jbd2_journal_wipe(journal->j_journal, full);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -847,9 +850,8 @@ static int ocfs2_force_read_journal(struct inode *inode)
/* We are reading journal data which should not
* be put in the uptodate cache */
- status = ocfs2_read_blocks(OCFS2_SB(inode->i_sb),
- p_blkno, p_blocks, bhs, 0,
- NULL);
+ status = ocfs2_read_blocks_sync(OCFS2_SB(inode->i_sb),
+ p_blkno, p_blocks, bhs);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -865,8 +867,7 @@ static int ocfs2_force_read_journal(struct inode *inode)
bail:
for(i = 0; i < CONCURRENT_JOURNAL_FILL; i++)
- if (bhs[i])
- brelse(bhs[i]);
+ brelse(bhs[i]);
mlog_exit(status);
return status;
}
@@ -1133,7 +1134,8 @@ static int ocfs2_read_journal_inode(struct ocfs2_super *osb,
}
SET_INODE_JOURNAL(inode);
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno, bh, 0, inode);
+ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1, bh,
+ OCFS2_BH_IGNORE_CACHE);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -1229,19 +1231,19 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
}
mlog(0, "calling journal_init_inode\n");
- journal = journal_init_inode(inode);
+ journal = jbd2_journal_init_inode(inode);
if (journal == NULL) {
mlog(ML_ERROR, "Linux journal layer error\n");
status = -EIO;
goto done;
}
- status = journal_load(journal);
+ status = jbd2_journal_load(journal);
if (status < 0) {
mlog_errno(status);
if (!igrab(inode))
BUG();
- journal_destroy(journal);
+ jbd2_journal_destroy(journal);
goto done;
}
@@ -1249,9 +1251,9 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
/* wipe the journal */
mlog(0, "flushing the journal.\n");
- journal_lock_updates(journal);
- status = journal_flush(journal);
- journal_unlock_updates(journal);
+ jbd2_journal_lock_updates(journal);
+ status = jbd2_journal_flush(journal);
+ jbd2_journal_unlock_updates(journal);
if (status < 0)
mlog_errno(status);
@@ -1272,7 +1274,7 @@ static int ocfs2_replay_journal(struct ocfs2_super *osb,
if (!igrab(inode))
BUG();
- journal_destroy(journal);
+ jbd2_journal_destroy(journal);
done:
/* drop the lock on this nodes journal */
@@ -1282,8 +1284,7 @@ done:
if (inode)
iput(inode);
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index 2178ebffa05..d4d14e9a3ce 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -27,7 +27,12 @@
#define OCFS2_JOURNAL_H
#include <linux/fs.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
enum ocfs2_journal_state {
OCFS2_JOURNAL_FREE = 0,
@@ -215,8 +220,8 @@ static inline void ocfs2_checkpoint_inode(struct inode *inode)
* buffer. Will have to call ocfs2_journal_dirty once
* we've actually dirtied it. Type is one of . or .
* ocfs2_journal_dirty - Mark a journalled buffer as having dirty data.
- * ocfs2_journal_dirty_data - Indicate that a data buffer should go out before
- * the current handle commits.
+ * ocfs2_jbd2_file_inode - Mark an inode so that its data goes out before
+ * the current handle commits.
*/
/* You must always start_trans with a number of buffs > 0, but it's
@@ -268,8 +273,10 @@ int ocfs2_journal_access(handle_t *handle,
*/
int ocfs2_journal_dirty(handle_t *handle,
struct buffer_head *bh);
+#ifdef CONFIG_OCFS2_COMPAT_JBD
int ocfs2_journal_dirty_data(handle_t *handle,
struct buffer_head *bh);
+#endif
/*
* Credit Macros:
@@ -283,6 +290,9 @@ int ocfs2_journal_dirty_data(handle_t *handle,
/* simple file updates like chmod, etc. */
#define OCFS2_INODE_UPDATE_CREDITS 1
+/* extended attribute block update */
+#define OCFS2_XATTR_BLOCK_UPDATE_CREDITS 1
+
/* group extend. inode update and last group update. */
#define OCFS2_GROUP_EXTEND_CREDITS (OCFS2_INODE_UPDATE_CREDITS + 1)
@@ -340,11 +350,23 @@ int ocfs2_journal_dirty_data(handle_t *handle,
#define OCFS2_RENAME_CREDITS (3 * OCFS2_INODE_UPDATE_CREDITS + 3 \
+ OCFS2_UNLINK_CREDITS)
+/* global bitmap dinode, group desc., relinked group,
+ * suballocator dinode, group desc., relinked group,
+ * dinode, xattr block */
+#define OCFS2_XATTR_BLOCK_CREATE_CREDITS (OCFS2_SUBALLOC_ALLOC * 2 + \
+ + OCFS2_INODE_UPDATE_CREDITS \
+ + OCFS2_XATTR_BLOCK_UPDATE_CREDITS)
+
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
static inline int ocfs2_calc_extend_credits(struct super_block *sb,
- struct ocfs2_dinode *fe,
+ struct ocfs2_extent_list *root_el,
u32 bits_wanted)
{
- int bitmap_blocks, sysfile_bitmap_blocks, dinode_blocks;
+ int bitmap_blocks, sysfile_bitmap_blocks, extent_blocks;
/* bitmap dinode, group desc. + relinked group. */
bitmap_blocks = OCFS2_SUBALLOC_ALLOC;
@@ -355,16 +377,16 @@ static inline int ocfs2_calc_extend_credits(struct super_block *sb,
* however many metadata chunks needed * a remaining suballoc
* alloc. */
sysfile_bitmap_blocks = 1 +
- (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(fe);
+ (OCFS2_SUBALLOC_ALLOC - 1) * ocfs2_extend_meta_needed(root_el);
/* this does not include *new* metadata blocks, which are
- * accounted for in sysfile_bitmap_blocks. fe +
+ * accounted for in sysfile_bitmap_blocks. root_el +
* prev. last_eb_blk + blocks along edge of tree.
* calc_symlink_credits passes because we just need 1
* credit for the dinode there. */
- dinode_blocks = 1 + 1 + le16_to_cpu(fe->id2.i_list.l_tree_depth);
+ extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
- return bitmap_blocks + sysfile_bitmap_blocks + dinode_blocks;
+ return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks;
}
static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
@@ -415,4 +437,16 @@ static inline int ocfs2_calc_tree_trunc_credits(struct super_block *sb,
return credits;
}
+static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode)
+{
+ return jbd2_journal_file_inode(handle, &OCFS2_I(inode)->ip_jinode);
+}
+
+static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
+ loff_t new_size)
+{
+ return jbd2_journal_begin_ordered_truncate(&OCFS2_I(inode)->ip_jinode,
+ new_size);
+}
+
#endif /* OCFS2_JOURNAL_H */
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index 28e492e4ec8..687b28713c3 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/bitops.h>
+#include <linux/debugfs.h>
#define MLOG_MASK_PREFIX ML_DISK_ALLOC
#include <cluster/masklog.h>
@@ -47,8 +48,6 @@
#define OCFS2_LOCAL_ALLOC(dinode) (&((dinode)->id2.i_lab))
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb);
-
static u32 ocfs2_local_alloc_count_bits(struct ocfs2_dinode *alloc);
static int ocfs2_local_alloc_find_clear_bits(struct ocfs2_super *osb,
@@ -75,24 +74,129 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
struct inode *local_alloc_inode);
-static inline int ocfs2_local_alloc_window_bits(struct ocfs2_super *osb)
+#ifdef CONFIG_OCFS2_FS_STATS
+
+static int ocfs2_la_debug_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+#define LA_DEBUG_BUF_SZ PAGE_CACHE_SIZE
+#define LA_DEBUG_VER 1
+static ssize_t ocfs2_la_debug_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ static DEFINE_MUTEX(la_debug_mutex);
+ struct ocfs2_super *osb = file->private_data;
+ int written, ret;
+ char *buf = osb->local_alloc_debug_buf;
+
+ mutex_lock(&la_debug_mutex);
+ memset(buf, 0, LA_DEBUG_BUF_SZ);
+
+ written = snprintf(buf, LA_DEBUG_BUF_SZ,
+ "0x%x\t0x%llx\t%u\t%u\t0x%x\n",
+ LA_DEBUG_VER,
+ (unsigned long long)osb->la_last_gd,
+ osb->local_alloc_default_bits,
+ osb->local_alloc_bits, osb->local_alloc_state);
+
+ ret = simple_read_from_buffer(userbuf, count, ppos, buf, written);
+
+ mutex_unlock(&la_debug_mutex);
+ return ret;
+}
+
+static const struct file_operations ocfs2_la_debug_fops = {
+ .open = ocfs2_la_debug_open,
+ .read = ocfs2_la_debug_read,
+};
+
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+ osb->local_alloc_debug_buf = kmalloc(LA_DEBUG_BUF_SZ, GFP_NOFS);
+ if (!osb->local_alloc_debug_buf)
+ return;
+
+ osb->local_alloc_debug = debugfs_create_file("local_alloc_stats",
+ S_IFREG|S_IRUSR,
+ osb->osb_debug_root,
+ osb,
+ &ocfs2_la_debug_fops);
+ if (!osb->local_alloc_debug) {
+ kfree(osb->local_alloc_debug_buf);
+ osb->local_alloc_debug_buf = NULL;
+ }
+}
+
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+ if (osb->local_alloc_debug)
+ debugfs_remove(osb->local_alloc_debug);
+
+ if (osb->local_alloc_debug_buf)
+ kfree(osb->local_alloc_debug_buf);
+
+ osb->local_alloc_debug_buf = NULL;
+ osb->local_alloc_debug = NULL;
+}
+#else /* CONFIG_OCFS2_FS_STATS */
+static void ocfs2_init_la_debug(struct ocfs2_super *osb)
+{
+ return;
+}
+static void ocfs2_shutdown_la_debug(struct ocfs2_super *osb)
+{
+ return;
+}
+#endif
+
+static inline int ocfs2_la_state_enabled(struct ocfs2_super *osb)
{
- BUG_ON(osb->s_clustersize_bits > 20);
+ return (osb->local_alloc_state == OCFS2_LA_THROTTLED ||
+ osb->local_alloc_state == OCFS2_LA_ENABLED);
+}
- /* Size local alloc windows by the megabyte */
- return osb->local_alloc_size << (20 - osb->s_clustersize_bits);
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+ unsigned int num_clusters)
+{
+ spin_lock(&osb->osb_lock);
+ if (osb->local_alloc_state == OCFS2_LA_DISABLED ||
+ osb->local_alloc_state == OCFS2_LA_THROTTLED)
+ if (num_clusters >= osb->local_alloc_default_bits) {
+ cancel_delayed_work(&osb->la_enable_wq);
+ osb->local_alloc_state = OCFS2_LA_ENABLED;
+ }
+ spin_unlock(&osb->osb_lock);
+}
+
+void ocfs2_la_enable_worker(struct work_struct *work)
+{
+ struct ocfs2_super *osb =
+ container_of(work, struct ocfs2_super,
+ la_enable_wq.work);
+ spin_lock(&osb->osb_lock);
+ osb->local_alloc_state = OCFS2_LA_ENABLED;
+ spin_unlock(&osb->osb_lock);
}
/*
* Tell us whether a given allocation should use the local alloc
* file. Otherwise, it has to go to the main bitmap.
+ *
+ * This function does semi-dirty reads of local alloc size and state!
+ * This is ok however, as the values are re-checked once under mutex.
*/
int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
{
- int la_bits = ocfs2_local_alloc_window_bits(osb);
int ret = 0;
+ int la_bits;
+
+ spin_lock(&osb->osb_lock);
+ la_bits = osb->local_alloc_bits;
- if (osb->local_alloc_state != OCFS2_LA_ENABLED)
+ if (!ocfs2_la_state_enabled(osb))
goto bail;
/* la_bits should be at least twice the size (in clusters) of
@@ -106,6 +210,7 @@ int ocfs2_alloc_should_use_local(struct ocfs2_super *osb, u64 bits)
bail:
mlog(0, "state=%d, bits=%llu, la_bits=%d, ret=%d\n",
osb->local_alloc_state, (unsigned long long)bits, la_bits, ret);
+ spin_unlock(&osb->osb_lock);
return ret;
}
@@ -120,14 +225,18 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
mlog_entry_void();
- if (osb->local_alloc_size == 0)
+ ocfs2_init_la_debug(osb);
+
+ if (osb->local_alloc_bits == 0)
goto bail;
- if (ocfs2_local_alloc_window_bits(osb) >= osb->bitmap_cpg) {
+ if (osb->local_alloc_bits >= osb->bitmap_cpg) {
mlog(ML_NOTICE, "Requested local alloc window %d is larger "
"than max possible %u. Using defaults.\n",
- ocfs2_local_alloc_window_bits(osb), (osb->bitmap_cpg - 1));
- osb->local_alloc_size = OCFS2_DEFAULT_LOCAL_ALLOC_SIZE;
+ osb->local_alloc_bits, (osb->bitmap_cpg - 1));
+ osb->local_alloc_bits =
+ ocfs2_megabytes_to_clusters(osb->sb,
+ OCFS2_DEFAULT_LOCAL_ALLOC_SIZE);
}
/* read the alloc off disk */
@@ -139,8 +248,8 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
goto bail;
}
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
- &alloc_bh, 0, inode);
+ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+ &alloc_bh, OCFS2_BH_IGNORE_CACHE);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -185,13 +294,14 @@ int ocfs2_load_local_alloc(struct ocfs2_super *osb)
bail:
if (status < 0)
- if (alloc_bh)
- brelse(alloc_bh);
+ brelse(alloc_bh);
if (inode)
iput(inode);
- mlog(0, "Local alloc window bits = %d\n",
- ocfs2_local_alloc_window_bits(osb));
+ if (status < 0)
+ ocfs2_shutdown_la_debug(osb);
+
+ mlog(0, "Local alloc window bits = %d\n", osb->local_alloc_bits);
mlog_exit(status);
return status;
@@ -217,6 +327,11 @@ void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb)
mlog_entry_void();
+ cancel_delayed_work(&osb->la_enable_wq);
+ flush_workqueue(ocfs2_wq);
+
+ ocfs2_shutdown_la_debug(osb);
+
if (osb->local_alloc_state == OCFS2_LA_UNUSED)
goto out;
@@ -295,8 +410,7 @@ out_commit:
ocfs2_commit_trans(osb, handle);
out_unlock:
- if (main_bm_bh)
- brelse(main_bm_bh);
+ brelse(main_bm_bh);
ocfs2_inode_unlock(main_bm_inode, 1);
@@ -345,8 +459,8 @@ int ocfs2_begin_local_alloc_recovery(struct ocfs2_super *osb,
mutex_lock(&inode->i_mutex);
- status = ocfs2_read_block(osb, OCFS2_I(inode)->ip_blkno,
- &alloc_bh, 0, inode);
+ status = ocfs2_read_blocks(inode, OCFS2_I(inode)->ip_blkno, 1,
+ &alloc_bh, OCFS2_BH_IGNORE_CACHE);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -372,8 +486,7 @@ bail:
*alloc_copy = NULL;
}
- if (alloc_bh)
- brelse(alloc_bh);
+ brelse(alloc_bh);
if (inode) {
mutex_unlock(&inode->i_mutex);
@@ -441,8 +554,7 @@ out_unlock:
out_mutex:
mutex_unlock(&main_bm_inode->i_mutex);
- if (main_bm_bh)
- brelse(main_bm_bh);
+ brelse(main_bm_bh);
iput(main_bm_inode);
@@ -453,8 +565,48 @@ out:
return status;
}
+/* Check to see if the local alloc window is within ac->ac_max_block */
+static int ocfs2_local_alloc_in_range(struct inode *inode,
+ struct ocfs2_alloc_context *ac,
+ u32 bits_wanted)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_dinode *alloc;
+ struct ocfs2_local_alloc *la;
+ int start;
+ u64 block_off;
+
+ if (!ac->ac_max_block)
+ return 1;
+
+ alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
+ la = OCFS2_LOCAL_ALLOC(alloc);
+
+ start = ocfs2_local_alloc_find_clear_bits(osb, alloc, bits_wanted);
+ if (start == -1) {
+ mlog_errno(-ENOSPC);
+ return 0;
+ }
+
+ /*
+ * Converting (bm_off + start + bits_wanted) to blocks gives us
+ * the blkno just past our actual allocation. This is perfect
+ * to compare with ac_max_block.
+ */
+ block_off = ocfs2_clusters_to_blocks(inode->i_sb,
+ le32_to_cpu(la->la_bm_off) +
+ start + bits_wanted);
+ mlog(0, "Checking %llu against %llu\n",
+ (unsigned long long)block_off,
+ (unsigned long long)ac->ac_max_block);
+ if (block_off > ac->ac_max_block)
+ return 0;
+
+ return 1;
+}
+
/*
- * make sure we've got at least bitswanted contiguous bits in the
+ * make sure we've got at least bits_wanted contiguous bits in the
* local alloc. You lose them when you drop i_mutex.
*
* We will add ourselves to the transaction passed in, but may start
@@ -485,16 +637,18 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
mutex_lock(&local_alloc_inode->i_mutex);
- if (osb->local_alloc_state != OCFS2_LA_ENABLED) {
- status = -ENOSPC;
- goto bail;
- }
-
- if (bits_wanted > ocfs2_local_alloc_window_bits(osb)) {
- mlog(0, "Asking for more than my max window size!\n");
+ /*
+ * We must double check state and allocator bits because
+ * another process may have changed them while holding i_mutex.
+ */
+ spin_lock(&osb->osb_lock);
+ if (!ocfs2_la_state_enabled(osb) ||
+ (bits_wanted > osb->local_alloc_bits)) {
+ spin_unlock(&osb->osb_lock);
status = -ENOSPC;
goto bail;
}
+ spin_unlock(&osb->osb_lock);
alloc = (struct ocfs2_dinode *) osb->local_alloc_bh->b_data;
@@ -522,6 +676,36 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb,
mlog_errno(status);
goto bail;
}
+
+ /*
+ * Under certain conditions, the window slide code
+ * might have reduced the number of bits available or
+ * disabled the the local alloc entirely. Re-check
+ * here and return -ENOSPC if necessary.
+ */
+ status = -ENOSPC;
+ if (!ocfs2_la_state_enabled(osb))
+ goto bail;
+
+ free_bits = le32_to_cpu(alloc->id1.bitmap1.i_total) -
+ le32_to_cpu(alloc->id1.bitmap1.i_used);
+ if (bits_wanted > free_bits)
+ goto bail;
+ }
+
+ if (ac->ac_max_block)
+ mlog(0, "Calling in_range for max block %llu\n",
+ (unsigned long long)ac->ac_max_block);
+
+ if (!ocfs2_local_alloc_in_range(local_alloc_inode, ac,
+ bits_wanted)) {
+ /*
+ * The window is outside ac->ac_max_block.
+ * This errno tells the caller to keep localalloc enabled
+ * but to get the allocation from the main bitmap.
+ */
+ status = -EFBIG;
+ goto bail;
}
ac->ac_inode = local_alloc_inode;
@@ -789,6 +973,85 @@ bail:
return status;
}
+enum ocfs2_la_event {
+ OCFS2_LA_EVENT_SLIDE, /* Normal window slide. */
+ OCFS2_LA_EVENT_FRAGMENTED, /* The global bitmap has
+ * enough bits theoretically
+ * free, but a contiguous
+ * allocation could not be
+ * found. */
+ OCFS2_LA_EVENT_ENOSPC, /* Global bitmap doesn't have
+ * enough bits free to satisfy
+ * our request. */
+};
+#define OCFS2_LA_ENABLE_INTERVAL (30 * HZ)
+/*
+ * Given an event, calculate the size of our next local alloc window.
+ *
+ * This should always be called under i_mutex of the local alloc inode
+ * so that local alloc disabling doesn't race with processes trying to
+ * use the allocator.
+ *
+ * Returns the state which the local alloc was left in. This value can
+ * be ignored by some paths.
+ */
+static int ocfs2_recalc_la_window(struct ocfs2_super *osb,
+ enum ocfs2_la_event event)
+{
+ unsigned int bits;
+ int state;
+
+ spin_lock(&osb->osb_lock);
+ if (osb->local_alloc_state == OCFS2_LA_DISABLED) {
+ WARN_ON_ONCE(osb->local_alloc_state == OCFS2_LA_DISABLED);
+ goto out_unlock;
+ }
+
+ /*
+ * ENOSPC and fragmentation are treated similarly for now.
+ */
+ if (event == OCFS2_LA_EVENT_ENOSPC ||
+ event == OCFS2_LA_EVENT_FRAGMENTED) {
+ /*
+ * We ran out of contiguous space in the primary
+ * bitmap. Drastically reduce the number of bits used
+ * by local alloc until we have to disable it.
+ */
+ bits = osb->local_alloc_bits >> 1;
+ if (bits > ocfs2_megabytes_to_clusters(osb->sb, 1)) {
+ /*
+ * By setting state to THROTTLED, we'll keep
+ * the number of local alloc bits used down
+ * until an event occurs which would give us
+ * reason to assume the bitmap situation might
+ * have changed.
+ */
+ osb->local_alloc_state = OCFS2_LA_THROTTLED;
+ osb->local_alloc_bits = bits;
+ } else {
+ osb->local_alloc_state = OCFS2_LA_DISABLED;
+ }
+ queue_delayed_work(ocfs2_wq, &osb->la_enable_wq,
+ OCFS2_LA_ENABLE_INTERVAL);
+ goto out_unlock;
+ }
+
+ /*
+ * Don't increase the size of the local alloc window until we
+ * know we might be able to fulfill the request. Otherwise, we
+ * risk bouncing around the global bitmap during periods of
+ * low space.
+ */
+ if (osb->local_alloc_state != OCFS2_LA_THROTTLED)
+ osb->local_alloc_bits = osb->local_alloc_default_bits;
+
+out_unlock:
+ state = osb->local_alloc_state;
+ spin_unlock(&osb->osb_lock);
+
+ return state;
+}
+
static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
struct ocfs2_alloc_context **ac,
struct inode **bitmap_inode,
@@ -803,12 +1066,21 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
goto bail;
}
- (*ac)->ac_bits_wanted = ocfs2_local_alloc_window_bits(osb);
+retry_enospc:
+ (*ac)->ac_bits_wanted = osb->local_alloc_bits;
status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
+ if (status == -ENOSPC) {
+ if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
+ OCFS2_LA_DISABLED)
+ goto bail;
+
+ ocfs2_free_ac_resource(*ac);
+ memset(*ac, 0, sizeof(struct ocfs2_alloc_context));
+ goto retry_enospc;
+ }
if (status < 0) {
- if (status != -ENOSPC)
- mlog_errno(status);
+ mlog_errno(status);
goto bail;
}
@@ -849,7 +1121,7 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
"one\n");
mlog(0, "Allocating %u clusters for a new window.\n",
- ocfs2_local_alloc_window_bits(osb));
+ osb->local_alloc_bits);
/* Instruct the allocation code to try the most recently used
* cluster group. We'll re-record the group used this pass
@@ -859,9 +1131,36 @@ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb,
/* we used the generic suballoc reserve function, but we set
* everything up nicely, so there's no reason why we can't use
* the more specific cluster api to claim bits. */
- status = ocfs2_claim_clusters(osb, handle, ac,
- ocfs2_local_alloc_window_bits(osb),
+ status = ocfs2_claim_clusters(osb, handle, ac, osb->local_alloc_bits,
&cluster_off, &cluster_count);
+ if (status == -ENOSPC) {
+retry_enospc:
+ /*
+ * Note: We could also try syncing the journal here to
+ * allow use of any free bits which the current
+ * transaction can't give us access to. --Mark
+ */
+ if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_FRAGMENTED) ==
+ OCFS2_LA_DISABLED)
+ goto bail;
+
+ status = ocfs2_claim_clusters(osb, handle, ac,
+ osb->local_alloc_bits,
+ &cluster_off,
+ &cluster_count);
+ if (status == -ENOSPC)
+ goto retry_enospc;
+ /*
+ * We only shrunk the *minimum* number of in our
+ * request - it's entirely possible that the allocator
+ * might give us more than we asked for.
+ */
+ if (status == 0) {
+ spin_lock(&osb->osb_lock);
+ osb->local_alloc_bits = cluster_count;
+ spin_unlock(&osb->osb_lock);
+ }
+ }
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -905,6 +1204,8 @@ static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb,
mlog_entry_void();
+ ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_SLIDE);
+
/* This will lock the main bitmap for us. */
status = ocfs2_local_alloc_reserve_for_window(osb,
&ac,
@@ -976,8 +1277,7 @@ bail:
if (handle)
ocfs2_commit_trans(osb, handle);
- if (main_bm_bh)
- brelse(main_bm_bh);
+ brelse(main_bm_bh);
if (main_bm_inode)
iput(main_bm_inode);
diff --git a/fs/ocfs2/localalloc.h b/fs/ocfs2/localalloc.h
index 3f76631e110..ac5ea9f8665 100644
--- a/fs/ocfs2/localalloc.h
+++ b/fs/ocfs2/localalloc.h
@@ -52,4 +52,8 @@ int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb,
u32 *bit_off,
u32 *num_bits);
+void ocfs2_local_alloc_seen_free_bits(struct ocfs2_super *osb,
+ unsigned int num_clusters);
+void ocfs2_la_enable_worker(struct work_struct *work);
+
#endif /* OCFS2_LOCALALLOC_H */
diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
index 203f8714387..544ac624517 100644
--- a/fs/ocfs2/locks.c
+++ b/fs/ocfs2/locks.c
@@ -24,6 +24,7 @@
*/
#include <linux/fs.h>
+#include <linux/fcntl.h>
#define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h>
@@ -32,6 +33,7 @@
#include "dlmglue.h"
#include "file.h"
+#include "inode.h"
#include "locks.h"
static int ocfs2_do_flock(struct file *file, struct inode *inode,
@@ -123,3 +125,16 @@ int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl)
else
return ocfs2_do_flock(file, inode, cmd, fl);
}
+
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct inode *inode = file->f_mapping->host;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ if (!(fl->fl_flags & FL_POSIX))
+ return -ENOLCK;
+ if (__mandatory_lock(inode))
+ return -ENOLCK;
+
+ return ocfs2_plock(osb->cconn, OCFS2_I(inode)->ip_blkno, file, cmd, fl);
+}
diff --git a/fs/ocfs2/locks.h b/fs/ocfs2/locks.h
index 9743ef2324e..496d488b271 100644
--- a/fs/ocfs2/locks.h
+++ b/fs/ocfs2/locks.h
@@ -27,5 +27,6 @@
#define OCFS2_LOCKS_H
int ocfs2_flock(struct file *file, int cmd, struct file_lock *fl);
+int ocfs2_lock(struct file *file, int cmd, struct file_lock *fl);
#endif /* OCFS2_LOCKS_H */
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index d5d808fe014..485a6aa0ad3 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -60,6 +60,7 @@
#include "symlink.h"
#include "sysfile.h"
#include "uptodate.h"
+#include "xattr.h"
#include "buffer_head_io.h"
@@ -327,14 +328,9 @@ leave:
if (status == -ENOSPC)
mlog(0, "Disk is full\n");
- if (new_fe_bh)
- brelse(new_fe_bh);
-
- if (de_bh)
- brelse(de_bh);
-
- if (parent_fe_bh)
- brelse(parent_fe_bh);
+ brelse(new_fe_bh);
+ brelse(de_bh);
+ brelse(parent_fe_bh);
if ((status < 0) && inode)
iput(inode);
@@ -647,12 +643,9 @@ out_unlock_inode:
out:
ocfs2_inode_unlock(dir, 1);
- if (de_bh)
- brelse(de_bh);
- if (fe_bh)
- brelse(fe_bh);
- if (parent_fe_bh)
- brelse(parent_fe_bh);
+ brelse(de_bh);
+ brelse(fe_bh);
+ brelse(parent_fe_bh);
mlog_exit(err);
@@ -851,17 +844,10 @@ leave:
iput(orphan_dir);
}
- if (fe_bh)
- brelse(fe_bh);
-
- if (dirent_bh)
- brelse(dirent_bh);
-
- if (parent_node_bh)
- brelse(parent_node_bh);
-
- if (orphan_entry_bh)
- brelse(orphan_entry_bh);
+ brelse(fe_bh);
+ brelse(dirent_bh);
+ brelse(parent_node_bh);
+ brelse(orphan_entry_bh);
mlog_exit(status);
@@ -1372,24 +1358,15 @@ bail:
if (new_inode)
iput(new_inode);
- if (newfe_bh)
- brelse(newfe_bh);
- if (old_inode_bh)
- brelse(old_inode_bh);
- if (old_dir_bh)
- brelse(old_dir_bh);
- if (new_dir_bh)
- brelse(new_dir_bh);
- if (new_de_bh)
- brelse(new_de_bh);
- if (old_de_bh)
- brelse(old_de_bh);
- if (old_inode_de_bh)
- brelse(old_inode_de_bh);
- if (orphan_entry_bh)
- brelse(orphan_entry_bh);
- if (insert_entry_bh)
- brelse(insert_entry_bh);
+ brelse(newfe_bh);
+ brelse(old_inode_bh);
+ brelse(old_dir_bh);
+ brelse(new_dir_bh);
+ brelse(new_de_bh);
+ brelse(old_de_bh);
+ brelse(old_inode_de_bh);
+ brelse(orphan_entry_bh);
+ brelse(insert_entry_bh);
mlog_exit(status);
@@ -1492,8 +1469,7 @@ bail:
if (bhs) {
for(i = 0; i < blocks; i++)
- if (bhs[i])
- brelse(bhs[i]);
+ brelse(bhs[i]);
kfree(bhs);
}
@@ -1598,10 +1574,10 @@ static int ocfs2_symlink(struct inode *dir,
u32 offset = 0;
inode->i_op = &ocfs2_symlink_inode_operations;
- status = ocfs2_do_extend_allocation(osb, inode, &offset, 1, 0,
- new_fe_bh,
- handle, data_ac, NULL,
- NULL);
+ status = ocfs2_add_inode_data(osb, inode, &offset, 1, 0,
+ new_fe_bh,
+ handle, data_ac, NULL,
+ NULL);
if (status < 0) {
if (status != -ENOSPC && status != -EINTR) {
mlog(ML_ERROR,
@@ -1659,12 +1635,9 @@ bail:
ocfs2_inode_unlock(dir, 1);
- if (new_fe_bh)
- brelse(new_fe_bh);
- if (parent_fe_bh)
- brelse(parent_fe_bh);
- if (de_bh)
- brelse(de_bh);
+ brelse(new_fe_bh);
+ brelse(parent_fe_bh);
+ brelse(de_bh);
if (inode_ac)
ocfs2_free_alloc_context(inode_ac);
if (data_ac)
@@ -1759,8 +1732,7 @@ leave:
iput(orphan_dir_inode);
}
- if (orphan_dir_bh)
- brelse(orphan_dir_bh);
+ brelse(orphan_dir_bh);
mlog_exit(status);
return status;
@@ -1780,10 +1752,9 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino);
- status = ocfs2_read_block(osb,
+ status = ocfs2_read_block(orphan_dir_inode,
OCFS2_I(orphan_dir_inode)->ip_blkno,
- &orphan_dir_bh, OCFS2_BH_CACHED,
- orphan_dir_inode);
+ &orphan_dir_bh);
if (status < 0) {
mlog_errno(status);
goto leave;
@@ -1829,8 +1800,7 @@ static int ocfs2_orphan_add(struct ocfs2_super *osb,
(unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num);
leave:
- if (orphan_dir_bh)
- brelse(orphan_dir_bh);
+ brelse(orphan_dir_bh);
mlog_exit(status);
return status;
@@ -1898,8 +1868,7 @@ int ocfs2_orphan_del(struct ocfs2_super *osb,
}
leave:
- if (target_de_bh)
- brelse(target_de_bh);
+ brelse(target_de_bh);
mlog_exit(status);
return status;
@@ -1918,4 +1887,8 @@ const struct inode_operations ocfs2_dir_iops = {
.setattr = ocfs2_setattr,
.getattr = ocfs2_getattr,
.permission = ocfs2_permission,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ocfs2_listxattr,
+ .removexattr = generic_removexattr,
};
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index 7f625f2b111..a21a465490c 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -34,7 +34,12 @@
#include <linux/workqueue.h>
#include <linux/kref.h>
#include <linux/mutex.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+# include "ocfs2_jbd_compat.h"
+#endif
/* For union ocfs2_dlm_lksb */
#include "stackglue.h"
@@ -171,9 +176,13 @@ struct ocfs2_alloc_stats
enum ocfs2_local_alloc_state
{
- OCFS2_LA_UNUSED = 0,
- OCFS2_LA_ENABLED,
- OCFS2_LA_DISABLED
+ OCFS2_LA_UNUSED = 0, /* Local alloc will never be used for
+ * this mountpoint. */
+ OCFS2_LA_ENABLED, /* Local alloc is in use. */
+ OCFS2_LA_THROTTLED, /* Local alloc is in use, but number
+ * of bits has been reduced. */
+ OCFS2_LA_DISABLED /* Local alloc has temporarily been
+ * disabled. */
};
enum ocfs2_mount_options
@@ -184,6 +193,8 @@ enum ocfs2_mount_options
OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */
OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */
OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */
+ OCFS2_MOUNT_NOUSERXATTR = 1 << 6, /* No user xattr */
+ OCFS2_MOUNT_INODE64 = 1 << 7, /* Allow inode numbers > 2^32 */
};
#define OCFS2_OSB_SOFT_RO 0x0001
@@ -214,6 +225,7 @@ struct ocfs2_super
u32 bitmap_cpg;
u8 *uuid;
char *uuid_str;
+ u32 uuid_hash;
u8 *vol_label;
u64 first_cluster_group_blkno;
u32 fs_generation;
@@ -241,6 +253,7 @@ struct ocfs2_super
int s_sectsize_bits;
int s_clustersize;
int s_clustersize_bits;
+ unsigned int s_xattr_inline_size;
atomic_t vol_state;
struct mutex recovery_lock;
@@ -252,11 +265,27 @@ struct ocfs2_super
struct ocfs2_journal *journal;
unsigned long osb_commit_interval;
- int local_alloc_size;
- enum ocfs2_local_alloc_state local_alloc_state;
+ struct delayed_work la_enable_wq;
+
+ /*
+ * Must hold local alloc i_mutex and osb->osb_lock to change
+ * local_alloc_bits. Reads can be done under either lock.
+ */
+ unsigned int local_alloc_bits;
+ unsigned int local_alloc_default_bits;
+
+ enum ocfs2_local_alloc_state local_alloc_state; /* protected
+ * by osb_lock */
+
struct buffer_head *local_alloc_bh;
+
u64 la_last_gd;
+#ifdef CONFIG_OCFS2_FS_STATS
+ struct dentry *local_alloc_debug;
+ char *local_alloc_debug_buf;
+#endif
+
/* Next two fields are for local node slot recovery during
* mount. */
int dirty;
@@ -340,6 +369,13 @@ static inline int ocfs2_supports_inline_data(struct ocfs2_super *osb)
return 0;
}
+static inline int ocfs2_supports_xattr(struct ocfs2_super *osb)
+{
+ if (osb->s_feature_incompat & OCFS2_FEATURE_INCOMPAT_XATTR)
+ return 1;
+ return 0;
+}
+
/* set / clear functions because cluster events can make these happen
* in parallel so we want the transitions to be atomic. this also
* means that any future flags osb_flags must be protected by spinlock
@@ -554,6 +590,14 @@ static inline unsigned int ocfs2_pages_per_cluster(struct super_block *sb)
return pages_per_cluster;
}
+static inline unsigned int ocfs2_megabytes_to_clusters(struct super_block *sb,
+ unsigned int megs)
+{
+ BUILD_BUG_ON(OCFS2_MAX_CLUSTERSIZE > 1048576);
+
+ return megs << (20 - OCFS2_SB(sb)->s_clustersize_bits);
+}
+
static inline void ocfs2_init_inode_steal_slot(struct ocfs2_super *osb)
{
spin_lock(&osb->osb_lock);
diff --git a/fs/ocfs2/ocfs2_fs.h b/fs/ocfs2/ocfs2_fs.h
index 4f619850ccf..f24ce3d3f95 100644
--- a/fs/ocfs2/ocfs2_fs.h
+++ b/fs/ocfs2/ocfs2_fs.h
@@ -64,6 +64,7 @@
#define OCFS2_INODE_SIGNATURE "INODE01"
#define OCFS2_EXTENT_BLOCK_SIGNATURE "EXBLK01"
#define OCFS2_GROUP_DESC_SIGNATURE "GROUP01"
+#define OCFS2_XATTR_BLOCK_SIGNATURE "XATTR01"
/* Compatibility flags */
#define OCFS2_HAS_COMPAT_FEATURE(sb,mask) \
@@ -90,7 +91,8 @@
| OCFS2_FEATURE_INCOMPAT_SPARSE_ALLOC \
| OCFS2_FEATURE_INCOMPAT_INLINE_DATA \
| OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP \
- | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK)
+ | OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK \
+ | OCFS2_FEATURE_INCOMPAT_XATTR)
#define OCFS2_FEATURE_RO_COMPAT_SUPP OCFS2_FEATURE_RO_COMPAT_UNWRITTEN
/*
@@ -127,10 +129,6 @@
/* Support for data packed into inode blocks */
#define OCFS2_FEATURE_INCOMPAT_INLINE_DATA 0x0040
-/* Support for the extended slot map */
-#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
-
-
/*
* Support for alternate, userspace cluster stacks. If set, the superblock
* field s_cluster_info contains a tag for the alternate stack in use as
@@ -142,6 +140,12 @@
*/
#define OCFS2_FEATURE_INCOMPAT_USERSPACE_STACK 0x0080
+/* Support for the extended slot map */
+#define OCFS2_FEATURE_INCOMPAT_EXTENDED_SLOT_MAP 0x100
+
+/* Support for extended attributes */
+#define OCFS2_FEATURE_INCOMPAT_XATTR 0x0200
+
/*
* backup superblock flag is used to indicate that this volume
* has backup superblocks.
@@ -299,6 +303,12 @@ struct ocfs2_new_group_input {
*/
#define OCFS2_DEFAULT_LOCAL_ALLOC_SIZE 8
+/*
+ * Inline extended attribute size (in bytes)
+ * The value chosen should be aligned to 16 byte boundaries.
+ */
+#define OCFS2_MIN_XATTR_INLINE_SIZE 256
+
struct ocfs2_system_inode_info {
char *si_name;
int si_iflags;
@@ -563,7 +573,7 @@ struct ocfs2_super_block {
/*40*/ __le16 s_max_slots; /* Max number of simultaneous mounts
before tunefs required */
__le16 s_tunefs_flag;
- __le32 s_reserved1;
+ __le32 s_uuid_hash; /* hash value of uuid */
__le64 s_first_cluster_group; /* Block offset of 1st cluster
* group header */
/*50*/ __u8 s_label[OCFS2_MAX_VOL_LABEL_LEN]; /* Label for mounting, etc. */
@@ -571,7 +581,11 @@ struct ocfs2_super_block {
/*A0*/ struct ocfs2_cluster_info s_cluster_info; /* Selected userspace
stack. Only valid
with INCOMPAT flag. */
-/*B8*/ __le64 s_reserved2[17]; /* Fill out superblock */
+/*B8*/ __le16 s_xattr_inline_size; /* extended attribute inline size
+ for this fs*/
+ __le16 s_reserved0;
+ __le32 s_reserved1;
+/*C0*/ __le64 s_reserved2[16]; /* Fill out superblock */
/*140*/
/*
@@ -621,7 +635,8 @@ struct ocfs2_dinode {
belongs to */
__le16 i_suballoc_bit; /* Bit offset in suballocator
block group */
-/*10*/ __le32 i_reserved0;
+/*10*/ __le16 i_reserved0;
+ __le16 i_xattr_inline_size;
__le32 i_clusters; /* Cluster count */
__le32 i_uid; /* Owner UID */
__le32 i_gid; /* Owning GID */
@@ -640,11 +655,12 @@ struct ocfs2_dinode {
__le32 i_atime_nsec;
__le32 i_ctime_nsec;
__le32 i_mtime_nsec;
- __le32 i_attr;
+/*70*/ __le32 i_attr;
__le16 i_orphaned_slot; /* Only valid when OCFS2_ORPHANED_FL
was set in i_flags */
__le16 i_dyn_features;
-/*70*/ __le64 i_reserved2[8];
+ __le64 i_xattr_loc;
+/*80*/ __le64 i_reserved2[7];
/*B8*/ union {
__le64 i_pad1; /* Generic way to refer to this
64bit union */
@@ -715,6 +731,136 @@ struct ocfs2_group_desc
/*40*/ __u8 bg_bitmap[0];
};
+/*
+ * On disk extended attribute structure for OCFS2.
+ */
+
+/*
+ * ocfs2_xattr_entry indicates one extend attribute.
+ *
+ * Note that it can be stored in inode, one block or one xattr bucket.
+ */
+struct ocfs2_xattr_entry {
+ __le32 xe_name_hash; /* hash value of xattr prefix+suffix. */
+ __le16 xe_name_offset; /* byte offset from the 1st etnry in the local
+ local xattr storage(inode, xattr block or
+ xattr bucket). */
+ __u8 xe_name_len; /* xattr name len, does't include prefix. */
+ __u8 xe_type; /* the low 7 bits indicates the name prefix's
+ * type and the highest 1 bits indicate whether
+ * the EA is stored in the local storage. */
+ __le64 xe_value_size; /* real xattr value length. */
+};
+
+/*
+ * On disk structure for xattr header.
+ *
+ * One ocfs2_xattr_header describes how many ocfs2_xattr_entry records in
+ * the local xattr storage.
+ */
+struct ocfs2_xattr_header {
+ __le16 xh_count; /* contains the count of how
+ many records are in the
+ local xattr storage. */
+ __le16 xh_free_start; /* current offset for storing
+ xattr. */
+ __le16 xh_name_value_len; /* total length of name/value
+ length in this bucket. */
+ __le16 xh_num_buckets; /* bucket nums in one extent
+ record, only valid in the
+ first bucket. */
+ __le64 xh_csum;
+ struct ocfs2_xattr_entry xh_entries[0]; /* xattr entry list. */
+};
+
+/*
+ * On disk structure for xattr value root.
+ *
+ * It is used when one extended attribute's size is larger, and we will save it
+ * in an outside cluster. It will stored in a b-tree like file content.
+ */
+struct ocfs2_xattr_value_root {
+/*00*/ __le32 xr_clusters; /* clusters covered by xattr value. */
+ __le32 xr_reserved0;
+ __le64 xr_last_eb_blk; /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xr_list; /* Extent record list */
+};
+
+/*
+ * On disk structure for xattr tree root.
+ *
+ * It is used when there are too many extended attributes for one file. These
+ * attributes will be organized and stored in an indexed-btree.
+ */
+struct ocfs2_xattr_tree_root {
+/*00*/ __le32 xt_clusters; /* clusters covered by xattr. */
+ __le32 xt_reserved0;
+ __le64 xt_last_eb_blk; /* Pointer to last extent block */
+/*10*/ struct ocfs2_extent_list xt_list; /* Extent record list */
+};
+
+#define OCFS2_XATTR_INDEXED 0x1
+#define OCFS2_HASH_SHIFT 5
+#define OCFS2_XATTR_ROUND 3
+#define OCFS2_XATTR_SIZE(size) (((size) + OCFS2_XATTR_ROUND) & \
+ ~(OCFS2_XATTR_ROUND))
+
+#define OCFS2_XATTR_BUCKET_SIZE 4096
+#define OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET (OCFS2_XATTR_BUCKET_SIZE \
+ / OCFS2_MIN_BLOCKSIZE)
+
+/*
+ * On disk structure for xattr block.
+ */
+struct ocfs2_xattr_block {
+/*00*/ __u8 xb_signature[8]; /* Signature for verification */
+ __le16 xb_suballoc_slot; /* Slot suballocator this
+ block belongs to. */
+ __le16 xb_suballoc_bit; /* Bit offset in suballocator
+ block group */
+ __le32 xb_fs_generation; /* Must match super block */
+/*10*/ __le64 xb_blkno; /* Offset on disk, in blocks */
+ __le64 xb_csum;
+/*20*/ __le16 xb_flags; /* Indicates whether this block contains
+ real xattr or a xattr tree. */
+ __le16 xb_reserved0;
+ __le32 xb_reserved1;
+ __le64 xb_reserved2;
+/*30*/ union {
+ struct ocfs2_xattr_header xb_header; /* xattr header if this
+ block contains xattr */
+ struct ocfs2_xattr_tree_root xb_root;/* xattr tree root if this
+ block cotains xattr
+ tree. */
+ } xb_attrs;
+};
+
+#define OCFS2_XATTR_ENTRY_LOCAL 0x80
+#define OCFS2_XATTR_TYPE_MASK 0x7F
+static inline void ocfs2_xattr_set_local(struct ocfs2_xattr_entry *xe,
+ int local)
+{
+ if (local)
+ xe->xe_type |= OCFS2_XATTR_ENTRY_LOCAL;
+ else
+ xe->xe_type &= ~OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline int ocfs2_xattr_is_local(struct ocfs2_xattr_entry *xe)
+{
+ return xe->xe_type & OCFS2_XATTR_ENTRY_LOCAL;
+}
+
+static inline void ocfs2_xattr_set_type(struct ocfs2_xattr_entry *xe, int type)
+{
+ xe->xe_type |= type & OCFS2_XATTR_TYPE_MASK;
+}
+
+static inline int ocfs2_xattr_get_type(struct ocfs2_xattr_entry *xe)
+{
+ return xe->xe_type & OCFS2_XATTR_TYPE_MASK;
+}
+
#ifdef __KERNEL__
static inline int ocfs2_fast_symlink_chars(struct super_block *sb)
{
@@ -728,6 +874,20 @@ static inline int ocfs2_max_inline_data(struct super_block *sb)
offsetof(struct ocfs2_dinode, id2.i_data.id_data);
}
+static inline int ocfs2_max_inline_data_with_xattr(struct super_block *sb,
+ struct ocfs2_dinode *di)
+{
+ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+ return sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_data.id_data) -
+ xattrsize;
+ else
+ return sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_data.id_data);
+}
+
static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
{
int size;
@@ -738,6 +898,24 @@ static inline int ocfs2_extent_recs_per_inode(struct super_block *sb)
return size / sizeof(struct ocfs2_extent_rec);
}
+static inline int ocfs2_extent_recs_per_inode_with_xattr(
+ struct super_block *sb,
+ struct ocfs2_dinode *di)
+{
+ int size;
+ unsigned int xattrsize = le16_to_cpu(di->i_xattr_inline_size);
+
+ if (le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_XATTR_FL)
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_list.l_recs) -
+ xattrsize;
+ else
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_dinode, id2.i_list.l_recs);
+
+ return size / sizeof(struct ocfs2_extent_rec);
+}
+
static inline int ocfs2_chain_recs_per_inode(struct super_block *sb)
{
int size;
@@ -801,6 +979,17 @@ static inline u64 ocfs2_backup_super_blkno(struct super_block *sb, int index)
return 0;
}
+
+static inline u16 ocfs2_xattr_recs_per_xb(struct super_block *sb)
+{
+ int size;
+
+ size = sb->s_blocksize -
+ offsetof(struct ocfs2_xattr_block,
+ xb_attrs.xb_root.xt_list.l_recs);
+
+ return size / sizeof(struct ocfs2_extent_rec);
+}
#else
static inline int ocfs2_fast_symlink_chars(int blocksize)
{
@@ -884,6 +1073,17 @@ static inline uint64_t ocfs2_backup_super_blkno(int blocksize, int index)
return 0;
}
+
+static inline int ocfs2_xattr_recs_per_xb(int blocksize)
+{
+ int size;
+
+ size = blocksize -
+ offsetof(struct ocfs2_xattr_block,
+ xb_attrs.xb_root.xt_list.l_recs);
+
+ return size / sizeof(struct ocfs2_extent_rec);
+}
#endif /* __KERNEL__ */
diff --git a/fs/ocfs2/ocfs2_jbd_compat.h b/fs/ocfs2/ocfs2_jbd_compat.h
new file mode 100644
index 00000000000..b91c78f8f55
--- /dev/null
+++ b/fs/ocfs2/ocfs2_jbd_compat.h
@@ -0,0 +1,82 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * ocfs2_jbd_compat.h
+ *
+ * Compatibility defines for JBD.
+ *
+ * Copyright (C) 2008 Oracle. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef OCFS2_JBD_COMPAT_H
+#define OCFS2_JBD_COMPAT_H
+
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# error Should not have been included
+#endif
+
+struct jbd2_inode {
+ unsigned int dummy;
+};
+
+#define JBD2_BARRIER JFS_BARRIER
+#define JBD2_DEFAULT_MAX_COMMIT_AGE JBD_DEFAULT_MAX_COMMIT_AGE
+
+#define jbd2_journal_ack_err journal_ack_err
+#define jbd2_journal_clear_err journal_clear_err
+#define jbd2_journal_destroy journal_destroy
+#define jbd2_journal_dirty_metadata journal_dirty_metadata
+#define jbd2_journal_errno journal_errno
+#define jbd2_journal_extend journal_extend
+#define jbd2_journal_flush journal_flush
+#define jbd2_journal_force_commit journal_force_commit
+#define jbd2_journal_get_write_access journal_get_write_access
+#define jbd2_journal_get_undo_access journal_get_undo_access
+#define jbd2_journal_init_inode journal_init_inode
+#define jbd2_journal_invalidatepage journal_invalidatepage
+#define jbd2_journal_load journal_load
+#define jbd2_journal_lock_updates journal_lock_updates
+#define jbd2_journal_restart journal_restart
+#define jbd2_journal_start journal_start
+#define jbd2_journal_start_commit journal_start_commit
+#define jbd2_journal_stop journal_stop
+#define jbd2_journal_try_to_free_buffers journal_try_to_free_buffers
+#define jbd2_journal_unlock_updates journal_unlock_updates
+#define jbd2_journal_wipe journal_wipe
+#define jbd2_log_wait_commit log_wait_commit
+
+static inline int jbd2_journal_file_inode(handle_t *handle,
+ struct jbd2_inode *inode)
+{
+ return 0;
+}
+
+static inline int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+ loff_t new_size)
+{
+ return 0;
+}
+
+static inline void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode,
+ struct inode *inode)
+{
+ return;
+}
+
+static inline void jbd2_journal_release_jbd_inode(journal_t *journal,
+ struct jbd2_inode *jinode)
+{
+ return;
+}
+
+
+#endif /* OCFS2_JBD_COMPAT_H */
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
index 8166968e901..ffd48db229a 100644
--- a/fs/ocfs2/resize.c
+++ b/fs/ocfs2/resize.c
@@ -200,7 +200,7 @@ static int update_backups(struct inode * inode, u32 clusters, char *data)
if (cluster > clusters)
break;
- ret = ocfs2_read_block(osb, blkno, &backup, 0, NULL);
+ ret = ocfs2_read_blocks_sync(osb, blkno, 1, &backup);
if (ret < 0) {
mlog_errno(ret);
break;
@@ -236,8 +236,8 @@ static void ocfs2_update_super_and_backups(struct inode *inode,
* update the superblock last.
* It doesn't matter if the write failed.
*/
- ret = ocfs2_read_block(osb, OCFS2_SUPER_BLOCK_BLKNO,
- &super_bh, 0, NULL);
+ ret = ocfs2_read_blocks_sync(osb, OCFS2_SUPER_BLOCK_BLKNO, 1,
+ &super_bh);
if (ret < 0) {
mlog_errno(ret);
goto out;
@@ -332,8 +332,7 @@ int ocfs2_group_extend(struct inode * inode, int new_clusters)
lgd_blkno = ocfs2_which_cluster_group(main_bm_inode,
first_new_cluster - 1);
- ret = ocfs2_read_block(osb, lgd_blkno, &group_bh, OCFS2_BH_CACHED,
- main_bm_inode);
+ ret = ocfs2_read_block(main_bm_inode, lgd_blkno, &group_bh);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
@@ -540,7 +539,7 @@ int ocfs2_group_add(struct inode *inode, struct ocfs2_new_group_input *input)
goto out_unlock;
}
- ret = ocfs2_read_block(osb, input->group, &group_bh, 0, NULL);
+ ret = ocfs2_read_blocks_sync(osb, input->group, 1, &group_bh);
if (ret < 0) {
mlog(ML_ERROR, "Can't read the group descriptor # %llu "
"from the device.", (unsigned long long)input->group);
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index bb5ff8939bf..bdda2d8f850 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -150,8 +150,8 @@ int ocfs2_refresh_slot_info(struct ocfs2_super *osb)
* be !NULL. Thus, ocfs2_read_blocks() will ignore blocknr. If
* this is not true, the read of -1 (UINT64_MAX) will fail.
*/
- ret = ocfs2_read_blocks(osb, -1, si->si_blocks, si->si_bh, 0,
- si->si_inode);
+ ret = ocfs2_read_blocks(si->si_inode, -1, si->si_blocks, si->si_bh,
+ OCFS2_BH_IGNORE_CACHE);
if (ret == 0) {
spin_lock(&osb->osb_lock);
ocfs2_update_slot_info(si);
@@ -404,7 +404,8 @@ static int ocfs2_map_slot_buffers(struct ocfs2_super *osb,
(unsigned long long)blkno);
bh = NULL; /* Acquire a fresh bh */
- status = ocfs2_read_block(osb, blkno, &bh, 0, si->si_inode);
+ status = ocfs2_read_blocks(si->si_inode, blkno, 1, &bh,
+ OCFS2_BH_IGNORE_CACHE);
if (status < 0) {
mlog_errno(status);
goto bail;
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 353fc35c674..faec2d87935 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -28,6 +28,7 @@
#include "ocfs2.h" /* For struct ocfs2_lock_res */
#include "stackglue.h"
+#include <linux/dlm_plock.h>
/*
* The control protocol starts with a handshake. Until the handshake
@@ -746,6 +747,37 @@ static void user_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb)
{
}
+static int user_plock(struct ocfs2_cluster_connection *conn,
+ u64 ino,
+ struct file *file,
+ int cmd,
+ struct file_lock *fl)
+{
+ /*
+ * This more or less just demuxes the plock request into any
+ * one of three dlm calls.
+ *
+ * Internally, fs/dlm will pass these to a misc device, which
+ * a userspace daemon will read and write to.
+ *
+ * For now, cancel requests (which happen internally only),
+ * are turned into unlocks. Most of this function taken from
+ * gfs2_lock.
+ */
+
+ if (cmd == F_CANCELLK) {
+ cmd = F_SETLK;
+ fl->fl_type = F_UNLCK;
+ }
+
+ if (IS_GETLK(cmd))
+ return dlm_posix_get(conn->cc_lockspace, ino, file, fl);
+ else if (fl->fl_type == F_UNLCK)
+ return dlm_posix_unlock(conn->cc_lockspace, ino, file, fl);
+ else
+ return dlm_posix_lock(conn->cc_lockspace, ino, file, cmd, fl);
+}
+
/*
* Compare a requested locking protocol version against the current one.
*
@@ -839,6 +871,7 @@ static struct ocfs2_stack_operations ocfs2_user_plugin_ops = {
.dlm_unlock = user_dlm_unlock,
.lock_status = user_dlm_lock_status,
.lock_lvb = user_dlm_lvb,
+ .plock = user_plock,
.dump_lksb = user_dlm_dump_lksb,
};
diff --git a/fs/ocfs2/stackglue.c b/fs/ocfs2/stackglue.c
index 07f348b8d72..68b668b0e60 100644
--- a/fs/ocfs2/stackglue.c
+++ b/fs/ocfs2/stackglue.c
@@ -288,6 +288,26 @@ void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb)
}
EXPORT_SYMBOL_GPL(ocfs2_dlm_dump_lksb);
+int ocfs2_stack_supports_plocks(void)
+{
+ return active_stack && active_stack->sp_ops->plock;
+}
+EXPORT_SYMBOL_GPL(ocfs2_stack_supports_plocks);
+
+/*
+ * ocfs2_plock() can only be safely called if
+ * ocfs2_stack_supports_plocks() returned true
+ */
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+ struct file *file, int cmd, struct file_lock *fl)
+{
+ WARN_ON_ONCE(active_stack->sp_ops->plock == NULL);
+ if (active_stack->sp_ops->plock)
+ return active_stack->sp_ops->plock(conn, ino, file, cmd, fl);
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(ocfs2_plock);
+
int ocfs2_cluster_connect(const char *stack_name,
const char *group,
int grouplen,
diff --git a/fs/ocfs2/stackglue.h b/fs/ocfs2/stackglue.h
index db56281dd1b..c571af375ef 100644
--- a/fs/ocfs2/stackglue.h
+++ b/fs/ocfs2/stackglue.h
@@ -28,6 +28,10 @@
#include "dlm/dlmapi.h"
#include <linux/dlm.h>
+/* Needed for plock-related prototypes */
+struct file;
+struct file_lock;
+
/*
* dlmconstants.h does not have a LOCAL flag. We hope to remove it
* some day, but right now we need it. Let's fake it. This value is larger
@@ -187,6 +191,17 @@ struct ocfs2_stack_operations {
void *(*lock_lvb)(union ocfs2_dlm_lksb *lksb);
/*
+ * Cluster-aware posix locks
+ *
+ * This is NULL for stacks which do not support posix locks.
+ */
+ int (*plock)(struct ocfs2_cluster_connection *conn,
+ u64 ino,
+ struct file *file,
+ int cmd,
+ struct file_lock *fl);
+
+ /*
* This is an optoinal debugging hook. If provided, the
* stack can dump debugging information about this lock.
*/
@@ -240,6 +255,10 @@ int ocfs2_dlm_lock_status(union ocfs2_dlm_lksb *lksb);
void *ocfs2_dlm_lvb(union ocfs2_dlm_lksb *lksb);
void ocfs2_dlm_dump_lksb(union ocfs2_dlm_lksb *lksb);
+int ocfs2_stack_supports_plocks(void);
+int ocfs2_plock(struct ocfs2_cluster_connection *conn, u64 ino,
+ struct file *file, int cmd, struct file_lock *fl);
+
void ocfs2_stack_glue_set_locking_protocol(struct ocfs2_locking_protocol *proto);
diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c
index d2d278fb981..c5ff18b46b5 100644
--- a/fs/ocfs2/suballoc.c
+++ b/fs/ocfs2/suballoc.c
@@ -62,15 +62,18 @@ static int ocfs2_block_group_fill(handle_t *handle,
struct ocfs2_chain_list *cl);
static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
struct inode *alloc_inode,
- struct buffer_head *bh);
+ struct buffer_head *bh,
+ u64 max_block);
static int ocfs2_cluster_group_search(struct inode *inode,
struct buffer_head *group_bh,
u32 bits_wanted, u32 min_bits,
+ u64 max_block,
u16 *bit_off, u16 *bits_found);
static int ocfs2_block_group_search(struct inode *inode,
struct buffer_head *group_bh,
u32 bits_wanted, u32 min_bits,
+ u64 max_block,
u16 *bit_off, u16 *bits_found);
static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb,
struct ocfs2_alloc_context *ac,
@@ -110,8 +113,11 @@ static inline void ocfs2_block_to_cluster_group(struct inode *inode,
u64 data_blkno,
u64 *bg_blkno,
u16 *bg_bit_off);
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+ u32 bits_wanted, u64 max_block,
+ struct ocfs2_alloc_context **ac);
-static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
{
struct inode *inode = ac->ac_inode;
@@ -124,10 +130,8 @@ static void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac)
iput(inode);
ac->ac_inode = NULL;
}
- if (ac->ac_bh) {
- brelse(ac->ac_bh);
- ac->ac_bh = NULL;
- }
+ brelse(ac->ac_bh);
+ ac->ac_bh = NULL;
}
void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac)
@@ -276,7 +280,8 @@ static inline u16 ocfs2_find_smallest_chain(struct ocfs2_chain_list *cl)
*/
static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
struct inode *alloc_inode,
- struct buffer_head *bh)
+ struct buffer_head *bh,
+ u64 max_block)
{
int status, credits;
struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data;
@@ -294,9 +299,9 @@ static int ocfs2_block_group_alloc(struct ocfs2_super *osb,
mlog_entry_void();
cl = &fe->id2.i_chain;
- status = ocfs2_reserve_clusters(osb,
- le16_to_cpu(cl->cl_cpg),
- &ac);
+ status = ocfs2_reserve_clusters_with_limit(osb,
+ le16_to_cpu(cl->cl_cpg),
+ max_block, &ac);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -394,8 +399,7 @@ bail:
if (ac)
ocfs2_free_alloc_context(ac);
- if (bg_bh)
- brelse(bg_bh);
+ brelse(bg_bh);
mlog_exit(status);
return status;
@@ -469,7 +473,8 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
goto bail;
}
- status = ocfs2_block_group_alloc(osb, alloc_inode, bh);
+ status = ocfs2_block_group_alloc(osb, alloc_inode, bh,
+ ac->ac_max_block);
if (status < 0) {
if (status != -ENOSPC)
mlog_errno(status);
@@ -486,16 +491,15 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb,
get_bh(bh);
ac->ac_bh = bh;
bail:
- if (bh)
- brelse(bh);
+ brelse(bh);
mlog_exit(status);
return status;
}
-int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
- struct ocfs2_dinode *fe,
- struct ocfs2_alloc_context **ac)
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+ int blocks,
+ struct ocfs2_alloc_context **ac)
{
int status;
u32 slot;
@@ -507,7 +511,7 @@ int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
goto bail;
}
- (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe);
+ (*ac)->ac_bits_wanted = blocks;
(*ac)->ac_which = OCFS2_AC_USE_META;
slot = osb->slot_num;
(*ac)->ac_group_search = ocfs2_block_group_search;
@@ -532,6 +536,15 @@ bail:
return status;
}
+int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
+ struct ocfs2_extent_list *root_el,
+ struct ocfs2_alloc_context **ac)
+{
+ return ocfs2_reserve_new_metadata_blocks(osb,
+ ocfs2_extend_meta_needed(root_el),
+ ac);
+}
+
static int ocfs2_steal_inode_from_other_nodes(struct ocfs2_super *osb,
struct ocfs2_alloc_context *ac)
{
@@ -582,6 +595,14 @@ int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
(*ac)->ac_group_search = ocfs2_block_group_search;
/*
+ * stat(2) can't handle i_ino > 32bits, so we tell the
+ * lower levels not to allocate us a block group past that
+ * limit. The 'inode64' mount option avoids this behavior.
+ */
+ if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64))
+ (*ac)->ac_max_block = (u32)~0U;
+
+ /*
* slot is set when we successfully steal inode from other nodes.
* It is reset in 3 places:
* 1. when we flush the truncate log
@@ -661,9 +682,9 @@ bail:
/* Callers don't need to care which bitmap (local alloc or main) to
* use so we figure it out for them, but unfortunately this clutters
* things a bit. */
-int ocfs2_reserve_clusters(struct ocfs2_super *osb,
- u32 bits_wanted,
- struct ocfs2_alloc_context **ac)
+static int ocfs2_reserve_clusters_with_limit(struct ocfs2_super *osb,
+ u32 bits_wanted, u64 max_block,
+ struct ocfs2_alloc_context **ac)
{
int status;
@@ -677,24 +698,20 @@ int ocfs2_reserve_clusters(struct ocfs2_super *osb,
}
(*ac)->ac_bits_wanted = bits_wanted;
+ (*ac)->ac_max_block = max_block;
status = -ENOSPC;
if (ocfs2_alloc_should_use_local(osb, bits_wanted)) {
status = ocfs2_reserve_local_alloc_bits(osb,
bits_wanted,
*ac);
- if ((status < 0) && (status != -ENOSPC)) {
+ if (status == -EFBIG) {
+ /* The local alloc window is outside ac_max_block.
+ * use the main bitmap. */
+ status = -ENOSPC;
+ } else if ((status < 0) && (status != -ENOSPC)) {
mlog_errno(status);
goto bail;
- } else if (status == -ENOSPC) {
- /* reserve_local_bits will return enospc with
- * the local alloc inode still locked, so we
- * can change this safely here. */
- mlog(0, "Disabling local alloc\n");
- /* We set to OCFS2_LA_DISABLED so that umount
- * can clean up what's left of the local
- * allocation */
- osb->local_alloc_state = OCFS2_LA_DISABLED;
}
}
@@ -718,6 +735,13 @@ bail:
return status;
}
+int ocfs2_reserve_clusters(struct ocfs2_super *osb,
+ u32 bits_wanted,
+ struct ocfs2_alloc_context **ac)
+{
+ return ocfs2_reserve_clusters_with_limit(osb, bits_wanted, 0, ac);
+}
+
/*
* More or less lifted from ext3. I'll leave their description below:
*
@@ -1000,11 +1024,14 @@ static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg
static int ocfs2_cluster_group_search(struct inode *inode,
struct buffer_head *group_bh,
u32 bits_wanted, u32 min_bits,
+ u64 max_block,
u16 *bit_off, u16 *bits_found)
{
int search = -ENOSPC;
int ret;
+ u64 blkoff;
struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *) group_bh->b_data;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
u16 tmp_off, tmp_found;
unsigned int max_bits, gd_cluster_off;
@@ -1037,6 +1064,17 @@ static int ocfs2_cluster_group_search(struct inode *inode,
if (ret)
return ret;
+ if (max_block) {
+ blkoff = ocfs2_clusters_to_blocks(inode->i_sb,
+ gd_cluster_off +
+ tmp_off + tmp_found);
+ mlog(0, "Checking %llu against %llu\n",
+ (unsigned long long)blkoff,
+ (unsigned long long)max_block);
+ if (blkoff > max_block)
+ return -ENOSPC;
+ }
+
/* ocfs2_block_group_find_clear_bits() might
* return success, but we still want to return
* -ENOSPC unless it found the minimum number
@@ -1045,6 +1083,12 @@ static int ocfs2_cluster_group_search(struct inode *inode,
*bit_off = tmp_off;
*bits_found = tmp_found;
search = 0; /* success */
+ } else if (tmp_found) {
+ /*
+ * Don't show bits which we'll be returning
+ * for allocation to the local alloc bitmap.
+ */
+ ocfs2_local_alloc_seen_free_bits(osb, tmp_found);
}
}
@@ -1054,19 +1098,31 @@ static int ocfs2_cluster_group_search(struct inode *inode,
static int ocfs2_block_group_search(struct inode *inode,
struct buffer_head *group_bh,
u32 bits_wanted, u32 min_bits,
+ u64 max_block,
u16 *bit_off, u16 *bits_found)
{
int ret = -ENOSPC;
+ u64 blkoff;
struct ocfs2_group_desc *bg = (struct ocfs2_group_desc *) group_bh->b_data;
BUG_ON(min_bits != 1);
BUG_ON(ocfs2_is_cluster_bitmap(inode));
- if (bg->bg_free_bits_count)
+ if (bg->bg_free_bits_count) {
ret = ocfs2_block_group_find_clear_bits(OCFS2_SB(inode->i_sb),
group_bh, bits_wanted,
le16_to_cpu(bg->bg_bits),
bit_off, bits_found);
+ if (!ret && max_block) {
+ blkoff = le64_to_cpu(bg->bg_blkno) + *bit_off +
+ *bits_found;
+ mlog(0, "Checking %llu against %llu\n",
+ (unsigned long long)blkoff,
+ (unsigned long long)max_block);
+ if (blkoff > max_block)
+ ret = -ENOSPC;
+ }
+ }
return ret;
}
@@ -1116,8 +1172,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
struct ocfs2_group_desc *gd;
struct inode *alloc_inode = ac->ac_inode;
- ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno,
- &group_bh, OCFS2_BH_CACHED, alloc_inode);
+ ret = ocfs2_read_block(alloc_inode, gd_blkno, &group_bh);
if (ret < 0) {
mlog_errno(ret);
return ret;
@@ -1131,7 +1186,7 @@ static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac,
}
ret = ac->ac_group_search(alloc_inode, group_bh, bits_wanted, min_bits,
- bit_off, &found);
+ ac->ac_max_block, bit_off, &found);
if (ret < 0) {
if (ret != -ENOSPC)
mlog_errno(ret);
@@ -1186,9 +1241,9 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
bits_wanted, chain,
(unsigned long long)OCFS2_I(alloc_inode)->ip_blkno);
- status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
+ status = ocfs2_read_block(alloc_inode,
le64_to_cpu(cl->cl_recs[chain].c_blkno),
- &group_bh, OCFS2_BH_CACHED, alloc_inode);
+ &group_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -1204,21 +1259,20 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
/* for now, the chain search is a bit simplistic. We just use
* the 1st group with any empty bits. */
while ((status = ac->ac_group_search(alloc_inode, group_bh,
- bits_wanted, min_bits, bit_off,
+ bits_wanted, min_bits,
+ ac->ac_max_block, bit_off,
&tmp_bits)) == -ENOSPC) {
if (!bg->bg_next_group)
break;
- if (prev_group_bh) {
- brelse(prev_group_bh);
- prev_group_bh = NULL;
- }
+ brelse(prev_group_bh);
+ prev_group_bh = NULL;
+
next_group = le64_to_cpu(bg->bg_next_group);
prev_group_bh = group_bh;
group_bh = NULL;
- status = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb),
- next_group, &group_bh,
- OCFS2_BH_CACHED, alloc_inode);
+ status = ocfs2_read_block(alloc_inode,
+ next_group, &group_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -1307,10 +1361,8 @@ static int ocfs2_search_chain(struct ocfs2_alloc_context *ac,
*bg_blkno = le64_to_cpu(bg->bg_blkno);
*bits_left = le16_to_cpu(bg->bg_free_bits_count);
bail:
- if (group_bh)
- brelse(group_bh);
- if (prev_group_bh)
- brelse(prev_group_bh);
+ brelse(group_bh);
+ brelse(prev_group_bh);
mlog_exit(status);
return status;
@@ -1723,7 +1775,6 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
{
int status = 0;
u32 tmp_used;
- struct ocfs2_super *osb = OCFS2_SB(alloc_inode->i_sb);
struct ocfs2_dinode *fe = (struct ocfs2_dinode *) alloc_bh->b_data;
struct ocfs2_chain_list *cl = &fe->id2.i_chain;
struct buffer_head *group_bh = NULL;
@@ -1742,8 +1793,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
(unsigned long long)OCFS2_I(alloc_inode)->ip_blkno, count,
(unsigned long long)bg_blkno, start_bit);
- status = ocfs2_read_block(osb, bg_blkno, &group_bh, OCFS2_BH_CACHED,
- alloc_inode);
+ status = ocfs2_read_block(alloc_inode, bg_blkno, &group_bh);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -1784,8 +1834,7 @@ int ocfs2_free_suballoc_bits(handle_t *handle,
}
bail:
- if (group_bh)
- brelse(group_bh);
+ brelse(group_bh);
mlog_exit(status);
return status;
@@ -1838,9 +1887,15 @@ int ocfs2_free_clusters(handle_t *handle,
status = ocfs2_free_suballoc_bits(handle, bitmap_inode, bitmap_bh,
bg_start_bit, bg_blkno,
num_clusters);
- if (status < 0)
+ if (status < 0) {
mlog_errno(status);
+ goto out;
+ }
+ ocfs2_local_alloc_seen_free_bits(OCFS2_SB(bitmap_inode->i_sb),
+ num_clusters);
+
+out:
mlog_exit(status);
return status;
}
@@ -1891,3 +1946,84 @@ static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe)
(unsigned long long)fe->id2.i_chain.cl_recs[i].c_blkno);
}
}
+
+/*
+ * For a given allocation, determine which allocators will need to be
+ * accessed, and lock them, reserving the appropriate number of bits.
+ *
+ * Sparse file systems call this from ocfs2_write_begin_nolock()
+ * and ocfs2_allocate_unwritten_extents().
+ *
+ * File systems which don't support holes call this from
+ * ocfs2_extend_allocation().
+ */
+int ocfs2_lock_allocators(struct inode *inode,
+ struct ocfs2_extent_tree *et,
+ u32 clusters_to_add, u32 extents_to_split,
+ struct ocfs2_alloc_context **data_ac,
+ struct ocfs2_alloc_context **meta_ac)
+{
+ int ret = 0, num_free_extents;
+ unsigned int max_recs_needed = clusters_to_add + 2 * extents_to_split;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ *meta_ac = NULL;
+ if (data_ac)
+ *data_ac = NULL;
+
+ BUG_ON(clusters_to_add != 0 && data_ac == NULL);
+
+ num_free_extents = ocfs2_num_free_extents(osb, inode, et);
+ if (num_free_extents < 0) {
+ ret = num_free_extents;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * Sparse allocation file systems need to be more conservative
+ * with reserving room for expansion - the actual allocation
+ * happens while we've got a journal handle open so re-taking
+ * a cluster lock (because we ran out of room for another
+ * extent) will violate ordering rules.
+ *
+ * Most of the time we'll only be seeing this 1 cluster at a time
+ * anyway.
+ *
+ * Always lock for any unwritten extents - we might want to
+ * add blocks during a split.
+ */
+ if (!num_free_extents ||
+ (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed)) {
+ ret = ocfs2_reserve_new_metadata(osb, et->et_root_el, meta_ac);
+ if (ret < 0) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ if (clusters_to_add == 0)
+ goto out;
+
+ ret = ocfs2_reserve_clusters(osb, clusters_to_add, data_ac);
+ if (ret < 0) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto out;
+ }
+
+out:
+ if (ret) {
+ if (*meta_ac) {
+ ocfs2_free_alloc_context(*meta_ac);
+ *meta_ac = NULL;
+ }
+
+ /*
+ * We cannot have an error and a non null *data_ac.
+ */
+ }
+
+ return ret;
+}
diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h
index 544c600662b..4df159d8f45 100644
--- a/fs/ocfs2/suballoc.h
+++ b/fs/ocfs2/suballoc.h
@@ -28,10 +28,11 @@
typedef int (group_search_t)(struct inode *,
struct buffer_head *,
- u32,
- u32,
- u16 *,
- u16 *);
+ u32, /* bits_wanted */
+ u32, /* min_bits */
+ u64, /* max_block */
+ u16 *, /* *bit_off */
+ u16 *); /* *bits_found */
struct ocfs2_alloc_context {
struct inode *ac_inode; /* which bitmap are we allocating from? */
@@ -51,6 +52,8 @@ struct ocfs2_alloc_context {
group_search_t *ac_group_search;
u64 ac_last_group;
+ u64 ac_max_block; /* Highest block number to allocate. 0 is
+ is the same as ~0 - unlimited */
};
void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac);
@@ -59,9 +62,17 @@ static inline int ocfs2_alloc_context_bits_left(struct ocfs2_alloc_context *ac)
return ac->ac_bits_wanted - ac->ac_bits_given;
}
+/*
+ * Please note that the caller must make sure that root_el is the root
+ * of extent tree. So for an inode, it should be &fe->id2.i_list. Otherwise
+ * the result may be wrong.
+ */
int ocfs2_reserve_new_metadata(struct ocfs2_super *osb,
- struct ocfs2_dinode *fe,
+ struct ocfs2_extent_list *root_el,
struct ocfs2_alloc_context **ac);
+int ocfs2_reserve_new_metadata_blocks(struct ocfs2_super *osb,
+ int blocks,
+ struct ocfs2_alloc_context **ac);
int ocfs2_reserve_new_inode(struct ocfs2_super *osb,
struct ocfs2_alloc_context **ac);
int ocfs2_reserve_clusters(struct ocfs2_super *osb,
@@ -147,6 +158,7 @@ static inline int ocfs2_is_cluster_bitmap(struct inode *inode)
* apis above. */
int ocfs2_reserve_cluster_bitmap_bits(struct ocfs2_super *osb,
struct ocfs2_alloc_context *ac);
+void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac);
/* given a cluster offset, calculate which block group it belongs to
* and return that block offset. */
@@ -156,4 +168,8 @@ u64 ocfs2_which_cluster_group(struct inode *inode, u32 cluster);
int ocfs2_check_group_descriptor(struct super_block *sb,
struct ocfs2_dinode *di,
struct ocfs2_group_desc *gd);
+int ocfs2_lock_allocators(struct inode *inode, struct ocfs2_extent_tree *et,
+ u32 clusters_to_add, u32 extents_to_split,
+ struct ocfs2_alloc_context **data_ac,
+ struct ocfs2_alloc_context **meta_ac);
#endif /* _CHAINALLOC_H_ */
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 70334d85aff..304b63ac78c 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -64,6 +64,7 @@
#include "sysfile.h"
#include "uptodate.h"
#include "ver.h"
+#include "xattr.h"
#include "buffer_head_io.h"
@@ -154,6 +155,9 @@ enum {
Opt_localalloc,
Opt_localflocks,
Opt_stack,
+ Opt_user_xattr,
+ Opt_nouser_xattr,
+ Opt_inode64,
Opt_err,
};
@@ -173,6 +177,9 @@ static const match_table_t tokens = {
{Opt_localalloc, "localalloc=%d"},
{Opt_localflocks, "localflocks"},
{Opt_stack, "cluster_stack=%s"},
+ {Opt_user_xattr, "user_xattr"},
+ {Opt_nouser_xattr, "nouser_xattr"},
+ {Opt_inode64, "inode64"},
{Opt_err, NULL}
};
@@ -205,10 +212,11 @@ static int ocfs2_sync_fs(struct super_block *sb, int wait)
ocfs2_schedule_truncate_log_flush(osb, 0);
}
- if (journal_start_commit(OCFS2_SB(sb)->journal->j_journal, &target)) {
+ if (jbd2_journal_start_commit(OCFS2_SB(sb)->journal->j_journal,
+ &target)) {
if (wait)
- log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
- target);
+ jbd2_log_wait_commit(OCFS2_SB(sb)->journal->j_journal,
+ target);
}
return 0;
}
@@ -325,6 +333,7 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb)
if (!oi)
return NULL;
+ jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode);
return &oi->vfs_inode;
}
@@ -406,6 +415,15 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
goto out;
}
+ /* Probably don't want this on remount; it might
+ * mess with other nodes */
+ if (!(osb->s_mount_opt & OCFS2_MOUNT_INODE64) &&
+ (parsed_options.mount_opt & OCFS2_MOUNT_INODE64)) {
+ ret = -EINVAL;
+ mlog(ML_ERROR, "Cannot enable inode64 on remount\n");
+ goto out;
+ }
+
/* We're going to/from readonly mode. */
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
/* Lock here so the check of HARD_RO and the potential
@@ -637,7 +655,8 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
osb->s_atime_quantum = parsed_options.atime_quantum;
osb->preferred_slot = parsed_options.slot;
osb->osb_commit_interval = parsed_options.commit_interval;
- osb->local_alloc_size = parsed_options.localalloc_opt;
+ osb->local_alloc_default_bits = ocfs2_megabytes_to_clusters(sb, parsed_options.localalloc_opt);
+ osb->local_alloc_bits = osb->local_alloc_default_bits;
status = ocfs2_verify_userspace_stack(osb, &parsed_options);
if (status)
@@ -743,8 +762,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
return status;
read_super_error:
- if (bh != NULL)
- brelse(bh);
+ brelse(bh);
if (inode)
iput(inode);
@@ -847,6 +865,12 @@ static int ocfs2_parse_options(struct super_block *sb,
case Opt_data_writeback:
mopt->mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK;
break;
+ case Opt_user_xattr:
+ mopt->mount_opt &= ~OCFS2_MOUNT_NOUSERXATTR;
+ break;
+ case Opt_nouser_xattr:
+ mopt->mount_opt |= OCFS2_MOUNT_NOUSERXATTR;
+ break;
case Opt_atime_quantum:
if (match_int(&args[0], &option)) {
status = 0;
@@ -873,7 +897,7 @@ static int ocfs2_parse_options(struct super_block *sb,
if (option < 0)
return 0;
if (option == 0)
- option = JBD_DEFAULT_MAX_COMMIT_AGE;
+ option = JBD2_DEFAULT_MAX_COMMIT_AGE;
mopt->commit_interval = HZ * option;
break;
case Opt_localalloc:
@@ -918,6 +942,9 @@ static int ocfs2_parse_options(struct super_block *sb,
OCFS2_STACK_LABEL_LEN);
mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0';
break;
+ case Opt_inode64:
+ mopt->mount_opt |= OCFS2_MOUNT_INODE64;
+ break;
default:
mlog(ML_ERROR,
"Unrecognized mount option \"%s\" "
@@ -938,6 +965,7 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
{
struct ocfs2_super *osb = OCFS2_SB(mnt->mnt_sb);
unsigned long opts = osb->s_mount_opt;
+ unsigned int local_alloc_megs;
if (opts & OCFS2_MOUNT_HB_LOCAL)
seq_printf(s, ",_netdev,heartbeat=local");
@@ -970,8 +998,9 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
seq_printf(s, ",commit=%u",
(unsigned) (osb->osb_commit_interval / HZ));
- if (osb->local_alloc_size != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
- seq_printf(s, ",localalloc=%d", osb->local_alloc_size);
+ local_alloc_megs = osb->local_alloc_bits >> (20 - osb->s_clustersize_bits);
+ if (local_alloc_megs != OCFS2_DEFAULT_LOCAL_ALLOC_SIZE)
+ seq_printf(s, ",localalloc=%d", local_alloc_megs);
if (opts & OCFS2_MOUNT_LOCALFLOCKS)
seq_printf(s, ",localflocks,");
@@ -980,6 +1009,14 @@ static int ocfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN,
osb->osb_cluster_stack);
+ if (opts & OCFS2_MOUNT_NOUSERXATTR)
+ seq_printf(s, ",nouser_xattr");
+ else
+ seq_printf(s, ",user_xattr");
+
+ if (opts & OCFS2_MOUNT_INODE64)
+ seq_printf(s, ",inode64");
+
return 0;
}
@@ -1132,6 +1169,7 @@ static void ocfs2_inode_init_once(void *data)
oi->ip_dir_start_lookup = 0;
init_rwsem(&oi->ip_alloc_sem);
+ init_rwsem(&oi->ip_xattr_sem);
mutex_init(&oi->ip_io_mutex);
oi->ip_blkno = 0ULL;
@@ -1375,6 +1413,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
sb->s_fs_info = osb;
sb->s_op = &ocfs2_sops;
sb->s_export_op = &ocfs2_export_ops;
+ sb->s_xattr = ocfs2_xattr_handlers;
sb->s_time_gran = 1;
sb->s_flags |= MS_NOATIME;
/* this is needed to support O_LARGEFILE */
@@ -1421,8 +1460,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
osb->slot_num = OCFS2_INVALID_SLOT;
+ osb->s_xattr_inline_size = le16_to_cpu(
+ di->id2.i_super.s_xattr_inline_size);
+
osb->local_alloc_state = OCFS2_LA_UNUSED;
osb->local_alloc_bh = NULL;
+ INIT_DELAYED_WORK(&osb->la_enable_wq, ocfs2_la_enable_worker);
init_waitqueue_head(&osb->osb_mount_event);
@@ -1568,6 +1611,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
osb->first_cluster_group_blkno =
le64_to_cpu(di->id2.i_super.s_first_cluster_group);
osb->fs_generation = le32_to_cpu(di->i_fs_generation);
+ osb->uuid_hash = le32_to_cpu(di->id2.i_super.s_uuid_hash);
mlog(0, "vol_label: %s\n", osb->vol_label);
mlog(0, "uuid: %s\n", osb->uuid_str);
mlog(0, "root_blkno=%llu, system_dir_blkno=%llu\n",
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index ba9dbb51d25..cbd03dfdc7b 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -50,6 +50,7 @@
#include "inode.h"
#include "journal.h"
#include "symlink.h"
+#include "xattr.h"
#include "buffer_head_io.h"
@@ -83,11 +84,7 @@ static char *ocfs2_fast_symlink_getlink(struct inode *inode,
mlog_entry_void();
- status = ocfs2_read_block(OCFS2_SB(inode->i_sb),
- OCFS2_I(inode)->ip_blkno,
- bh,
- OCFS2_BH_CACHED,
- inode);
+ status = ocfs2_read_block(inode, OCFS2_I(inode)->ip_blkno, bh);
if (status < 0) {
mlog_errno(status);
link = ERR_PTR(status);
@@ -157,8 +154,7 @@ bail:
kunmap(page);
page_cache_release(page);
}
- if (bh)
- brelse(bh);
+ brelse(bh);
return ERR_PTR(status);
}
@@ -168,10 +164,18 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ocfs2_listxattr,
+ .removexattr = generic_removexattr,
};
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
.readlink = ocfs2_readlink,
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ocfs2_listxattr,
+ .removexattr = generic_removexattr,
};
diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c
index 4da8851f2b2..187b99ff036 100644
--- a/fs/ocfs2/uptodate.c
+++ b/fs/ocfs2/uptodate.c
@@ -53,7 +53,11 @@
#include <linux/highmem.h>
#include <linux/buffer_head.h>
#include <linux/rbtree.h>
-#include <linux/jbd.h>
+#ifndef CONFIG_OCFS2_COMPAT_JBD
+# include <linux/jbd2.h>
+#else
+# include <linux/jbd.h>
+#endif
#define MLOG_MASK_PREFIX ML_UPTODATE
@@ -511,14 +515,10 @@ static void ocfs2_remove_metadata_tree(struct ocfs2_caching_info *ci,
ci->ci_num_cached--;
}
-/* Called when we remove a chunk of metadata from an inode. We don't
- * bother reverting things to an inlined array in the case of a remove
- * which moves us back under the limit. */
-void ocfs2_remove_from_cache(struct inode *inode,
- struct buffer_head *bh)
+static void ocfs2_remove_block_from_cache(struct inode *inode,
+ sector_t block)
{
int index;
- sector_t block = bh->b_blocknr;
struct ocfs2_meta_cache_item *item = NULL;
struct ocfs2_inode_info *oi = OCFS2_I(inode);
struct ocfs2_caching_info *ci = &oi->ip_metadata_cache;
@@ -544,6 +544,30 @@ void ocfs2_remove_from_cache(struct inode *inode,
kmem_cache_free(ocfs2_uptodate_cachep, item);
}
+/*
+ * Called when we remove a chunk of metadata from an inode. We don't
+ * bother reverting things to an inlined array in the case of a remove
+ * which moves us back under the limit.
+ */
+void ocfs2_remove_from_cache(struct inode *inode,
+ struct buffer_head *bh)
+{
+ sector_t block = bh->b_blocknr;
+
+ ocfs2_remove_block_from_cache(inode, block);
+}
+
+/* Called when we remove xattr clusters from an inode. */
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+ sector_t block,
+ u32 c_len)
+{
+ unsigned int i, b_len = ocfs2_clusters_to_blocks(inode->i_sb, 1) * c_len;
+
+ for (i = 0; i < b_len; i++, block++)
+ ocfs2_remove_block_from_cache(inode, block);
+}
+
int __init init_ocfs2_uptodate_cache(void)
{
ocfs2_uptodate_cachep = kmem_cache_create("ocfs2_uptodate",
diff --git a/fs/ocfs2/uptodate.h b/fs/ocfs2/uptodate.h
index 2e73206059a..531b4b3a0c4 100644
--- a/fs/ocfs2/uptodate.h
+++ b/fs/ocfs2/uptodate.h
@@ -40,6 +40,9 @@ void ocfs2_set_new_buffer_uptodate(struct inode *inode,
struct buffer_head *bh);
void ocfs2_remove_from_cache(struct inode *inode,
struct buffer_head *bh);
+void ocfs2_remove_xattr_clusters_from_cache(struct inode *inode,
+ sector_t block,
+ u32 c_len);
int ocfs2_buffer_read_ahead(struct inode *inode,
struct buffer_head *bh);
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
new file mode 100644
index 00000000000..802c4149221
--- /dev/null
+++ b/fs/ocfs2/xattr.c
@@ -0,0 +1,4832 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.c
+ *
+ * Copyright (C) 2008 Oracle. All rights reserved.
+ *
+ * CREDITS:
+ * Lots of code in this file is taken from ext3.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/sched.h>
+#include <linux/splice.h>
+#include <linux/mount.h>
+#include <linux/writeback.h>
+#include <linux/falloc.h>
+#include <linux/sort.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#define MLOG_MASK_PREFIX ML_XATTR
+#include <cluster/masklog.h>
+
+#include "ocfs2.h"
+#include "alloc.h"
+#include "dlmglue.h"
+#include "file.h"
+#include "symlink.h"
+#include "sysfile.h"
+#include "inode.h"
+#include "journal.h"
+#include "ocfs2_fs.h"
+#include "suballoc.h"
+#include "uptodate.h"
+#include "buffer_head_io.h"
+#include "super.h"
+#include "xattr.h"
+
+
+struct ocfs2_xattr_def_value_root {
+ struct ocfs2_xattr_value_root xv;
+ struct ocfs2_extent_rec er;
+};
+
+struct ocfs2_xattr_bucket {
+ struct buffer_head *bhs[OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET];
+ struct ocfs2_xattr_header *xh;
+};
+
+#define OCFS2_XATTR_ROOT_SIZE (sizeof(struct ocfs2_xattr_def_value_root))
+#define OCFS2_XATTR_INLINE_SIZE 80
+
+static struct ocfs2_xattr_def_value_root def_xv = {
+ .xv.xr_list.l_count = cpu_to_le16(1),
+};
+
+struct xattr_handler *ocfs2_xattr_handlers[] = {
+ &ocfs2_xattr_user_handler,
+ &ocfs2_xattr_trusted_handler,
+ NULL
+};
+
+static struct xattr_handler *ocfs2_xattr_handler_map[] = {
+ [OCFS2_XATTR_INDEX_USER] = &ocfs2_xattr_user_handler,
+ [OCFS2_XATTR_INDEX_TRUSTED] = &ocfs2_xattr_trusted_handler,
+};
+
+struct ocfs2_xattr_info {
+ int name_index;
+ const char *name;
+ const void *value;
+ size_t value_len;
+};
+
+struct ocfs2_xattr_search {
+ struct buffer_head *inode_bh;
+ /*
+ * xattr_bh point to the block buffer head which has extended attribute
+ * when extended attribute in inode, xattr_bh is equal to inode_bh.
+ */
+ struct buffer_head *xattr_bh;
+ struct ocfs2_xattr_header *header;
+ struct ocfs2_xattr_bucket bucket;
+ void *base;
+ void *end;
+ struct ocfs2_xattr_entry *here;
+ int not_found;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+ struct ocfs2_xattr_header *xh,
+ int index,
+ int *block_off,
+ int *new_offset);
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+ struct buffer_head *root_bh,
+ int name_index,
+ const char *name,
+ struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+ struct ocfs2_xattr_tree_root *xt,
+ char *buffer,
+ size_t buffer_size);
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+ struct ocfs2_xattr_search *xs);
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs);
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+ struct buffer_head *xb_bh);
+
+static inline const char *ocfs2_xattr_prefix(int name_index)
+{
+ struct xattr_handler *handler = NULL;
+
+ if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
+ handler = ocfs2_xattr_handler_map[name_index];
+
+ return handler ? handler->prefix : NULL;
+}
+
+static u32 ocfs2_xattr_name_hash(struct inode *inode,
+ const char *name,
+ int name_len)
+{
+ /* Get hash value of uuid from super block */
+ u32 hash = OCFS2_SB(inode->i_sb)->uuid_hash;
+ int i;
+
+ /* hash extended attribute name */
+ for (i = 0; i < name_len; i++) {
+ hash = (hash << OCFS2_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - OCFS2_HASH_SHIFT)) ^
+ *name++;
+ }
+
+ return hash;
+}
+
+/*
+ * ocfs2_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+static void ocfs2_xattr_hash_entry(struct inode *inode,
+ struct ocfs2_xattr_header *header,
+ struct ocfs2_xattr_entry *entry)
+{
+ u32 hash = 0;
+ char *name = (char *)header + le16_to_cpu(entry->xe_name_offset);
+
+ hash = ocfs2_xattr_name_hash(inode, name, entry->xe_name_len);
+ entry->xe_name_hash = cpu_to_le32(hash);
+
+ return;
+}
+
+static int ocfs2_xattr_extend_allocation(struct inode *inode,
+ u32 clusters_to_add,
+ struct buffer_head *xattr_bh,
+ struct ocfs2_xattr_value_root *xv)
+{
+ int status = 0;
+ int restart_func = 0;
+ int credits = 0;
+ handle_t *handle = NULL;
+ struct ocfs2_alloc_context *data_ac = NULL;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ enum ocfs2_alloc_restarted why;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ u32 prev_clusters, logical_start = le32_to_cpu(xv->xr_clusters);
+ struct ocfs2_extent_tree et;
+
+ mlog(0, "(clusters_to_add for xattr= %u)\n", clusters_to_add);
+
+ ocfs2_init_xattr_value_extent_tree(&et, inode, xattr_bh, xv);
+
+restart_all:
+
+ status = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+ &data_ac, &meta_ac);
+ if (status) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+ clusters_to_add);
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ status = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(status);
+ goto leave;
+ }
+
+restarted_transaction:
+ status = ocfs2_journal_access(handle, inode, xattr_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ prev_clusters = le32_to_cpu(xv->xr_clusters);
+ status = ocfs2_add_clusters_in_btree(osb,
+ inode,
+ &logical_start,
+ clusters_to_add,
+ 0,
+ &et,
+ handle,
+ data_ac,
+ meta_ac,
+ &why);
+ if ((status < 0) && (status != -EAGAIN)) {
+ if (status != -ENOSPC)
+ mlog_errno(status);
+ goto leave;
+ }
+
+ status = ocfs2_journal_dirty(handle, xattr_bh);
+ if (status < 0) {
+ mlog_errno(status);
+ goto leave;
+ }
+
+ clusters_to_add -= le32_to_cpu(xv->xr_clusters) - prev_clusters;
+
+ if (why != RESTART_NONE && clusters_to_add) {
+ if (why == RESTART_META) {
+ mlog(0, "restarting function.\n");
+ restart_func = 1;
+ } else {
+ BUG_ON(why != RESTART_TRANS);
+
+ mlog(0, "restarting transaction.\n");
+ /* TODO: This can be more intelligent. */
+ credits = ocfs2_calc_extend_credits(osb->sb,
+ et.et_root_el,
+ clusters_to_add);
+ status = ocfs2_extend_trans(handle, credits);
+ if (status < 0) {
+ /* handle still has to be committed at
+ * this point. */
+ status = -ENOMEM;
+ mlog_errno(status);
+ goto leave;
+ }
+ goto restarted_transaction;
+ }
+ }
+
+leave:
+ if (handle) {
+ ocfs2_commit_trans(osb, handle);
+ handle = NULL;
+ }
+ if (data_ac) {
+ ocfs2_free_alloc_context(data_ac);
+ data_ac = NULL;
+ }
+ if (meta_ac) {
+ ocfs2_free_alloc_context(meta_ac);
+ meta_ac = NULL;
+ }
+ if ((!status) && restart_func) {
+ restart_func = 0;
+ goto restart_all;
+ }
+
+ return status;
+}
+
+static int __ocfs2_remove_xattr_range(struct inode *inode,
+ struct buffer_head *root_bh,
+ struct ocfs2_xattr_value_root *xv,
+ u32 cpos, u32 phys_cpos, u32 len,
+ struct ocfs2_cached_dealloc_ctxt *dealloc)
+{
+ int ret;
+ u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct inode *tl_inode = osb->osb_tl_inode;
+ handle_t *handle;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ struct ocfs2_extent_tree et;
+
+ ocfs2_init_xattr_value_extent_tree(&et, inode, root_bh, xv);
+
+ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ mutex_lock(&tl_inode->i_mutex);
+
+ if (ocfs2_truncate_log_needs_flush(osb)) {
+ ret = __ocfs2_flush_truncate_log(osb);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, root_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+ dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ le32_add_cpu(&xv->xr_clusters, -len);
+
+ ret = ocfs2_journal_dirty(handle, root_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
+ if (ret)
+ mlog_errno(ret);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ mutex_unlock(&tl_inode->i_mutex);
+
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+
+ return ret;
+}
+
+static int ocfs2_xattr_shrink_size(struct inode *inode,
+ u32 old_clusters,
+ u32 new_clusters,
+ struct buffer_head *root_bh,
+ struct ocfs2_xattr_value_root *xv)
+{
+ int ret = 0;
+ u32 trunc_len, cpos, phys_cpos, alloc_size;
+ u64 block;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_cached_dealloc_ctxt dealloc;
+
+ ocfs2_init_dealloc_ctxt(&dealloc);
+
+ if (old_clusters <= new_clusters)
+ return 0;
+
+ cpos = new_clusters;
+ trunc_len = old_clusters - new_clusters;
+ while (trunc_len) {
+ ret = ocfs2_xattr_get_clusters(inode, cpos, &phys_cpos,
+ &alloc_size, &xv->xr_list);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (alloc_size > trunc_len)
+ alloc_size = trunc_len;
+
+ ret = __ocfs2_remove_xattr_range(inode, root_bh, xv, cpos,
+ phys_cpos, alloc_size,
+ &dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ block = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
+ ocfs2_remove_xattr_clusters_from_cache(inode, block,
+ alloc_size);
+ cpos += alloc_size;
+ trunc_len -= alloc_size;
+ }
+
+out:
+ ocfs2_schedule_truncate_log_flush(osb, 1);
+ ocfs2_run_deallocs(osb, &dealloc);
+
+ return ret;
+}
+
+static int ocfs2_xattr_value_truncate(struct inode *inode,
+ struct buffer_head *root_bh,
+ struct ocfs2_xattr_value_root *xv,
+ int len)
+{
+ int ret;
+ u32 new_clusters = ocfs2_clusters_for_bytes(inode->i_sb, len);
+ u32 old_clusters = le32_to_cpu(xv->xr_clusters);
+
+ if (new_clusters == old_clusters)
+ return 0;
+
+ if (new_clusters > old_clusters)
+ ret = ocfs2_xattr_extend_allocation(inode,
+ new_clusters - old_clusters,
+ root_bh, xv);
+ else
+ ret = ocfs2_xattr_shrink_size(inode,
+ old_clusters, new_clusters,
+ root_bh, xv);
+
+ return ret;
+}
+
+static int ocfs2_xattr_list_entry(char *buffer, size_t size,
+ size_t *result, const char *prefix,
+ const char *name, int name_len)
+{
+ char *p = buffer + *result;
+ int prefix_len = strlen(prefix);
+ int total_len = prefix_len + name_len + 1;
+
+ *result += total_len;
+
+ /* we are just looking for how big our buffer needs to be */
+ if (!size)
+ return 0;
+
+ if (*result > size)
+ return -ERANGE;
+
+ memcpy(p, prefix, prefix_len);
+ memcpy(p + prefix_len, name, name_len);
+ p[prefix_len + name_len] = '\0';
+
+ return 0;
+}
+
+static int ocfs2_xattr_list_entries(struct inode *inode,
+ struct ocfs2_xattr_header *header,
+ char *buffer, size_t buffer_size)
+{
+ size_t result = 0;
+ int i, type, ret;
+ const char *prefix, *name;
+
+ for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
+ struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+ type = ocfs2_xattr_get_type(entry);
+ prefix = ocfs2_xattr_prefix(type);
+
+ if (prefix) {
+ name = (const char *)header +
+ le16_to_cpu(entry->xe_name_offset);
+
+ ret = ocfs2_xattr_list_entry(buffer, buffer_size,
+ &result, prefix, name,
+ entry->xe_name_len);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return result;
+}
+
+static int ocfs2_xattr_ibody_list(struct inode *inode,
+ struct ocfs2_dinode *di,
+ char *buffer,
+ size_t buffer_size)
+{
+ struct ocfs2_xattr_header *header = NULL;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ int ret = 0;
+
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+ return ret;
+
+ header = (struct ocfs2_xattr_header *)
+ ((void *)di + inode->i_sb->s_blocksize -
+ le16_to_cpu(di->i_xattr_inline_size));
+
+ ret = ocfs2_xattr_list_entries(inode, header, buffer, buffer_size);
+
+ return ret;
+}
+
+static int ocfs2_xattr_block_list(struct inode *inode,
+ struct ocfs2_dinode *di,
+ char *buffer,
+ size_t buffer_size)
+{
+ struct buffer_head *blk_bh = NULL;
+ struct ocfs2_xattr_block *xb;
+ int ret = 0;
+
+ if (!di->i_xattr_loc)
+ return ret;
+
+ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ /*Verify the signature of xattr block*/
+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ struct ocfs2_xattr_header *header = &xb->xb_attrs.xb_header;
+ ret = ocfs2_xattr_list_entries(inode, header,
+ buffer, buffer_size);
+ } else {
+ struct ocfs2_xattr_tree_root *xt = &xb->xb_attrs.xb_root;
+ ret = ocfs2_xattr_tree_list_index_block(inode, xt,
+ buffer, buffer_size);
+ }
+cleanup:
+ brelse(blk_bh);
+
+ return ret;
+}
+
+ssize_t ocfs2_listxattr(struct dentry *dentry,
+ char *buffer,
+ size_t size)
+{
+ int ret = 0, i_ret = 0, b_ret = 0;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_dinode *di = NULL;
+ struct ocfs2_inode_info *oi = OCFS2_I(dentry->d_inode);
+
+ if (!ocfs2_supports_xattr(OCFS2_SB(dentry->d_sb)))
+ return -EOPNOTSUPP;
+
+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+ return ret;
+
+ ret = ocfs2_inode_lock(dentry->d_inode, &di_bh, 0);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ down_read(&oi->ip_xattr_sem);
+ i_ret = ocfs2_xattr_ibody_list(dentry->d_inode, di, buffer, size);
+ if (i_ret < 0)
+ b_ret = 0;
+ else {
+ if (buffer) {
+ buffer += i_ret;
+ size -= i_ret;
+ }
+ b_ret = ocfs2_xattr_block_list(dentry->d_inode, di,
+ buffer, size);
+ if (b_ret < 0)
+ i_ret = 0;
+ }
+ up_read(&oi->ip_xattr_sem);
+ ocfs2_inode_unlock(dentry->d_inode, 0);
+
+ brelse(di_bh);
+
+ return i_ret + b_ret;
+}
+
+static int ocfs2_xattr_find_entry(int name_index,
+ const char *name,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_xattr_entry *entry;
+ size_t name_len;
+ int i, cmp = 1;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ name_len = strlen(name);
+ entry = xs->here;
+ for (i = 0; i < le16_to_cpu(xs->header->xh_count); i++) {
+ cmp = name_index - ocfs2_xattr_get_type(entry);
+ if (!cmp)
+ cmp = name_len - entry->xe_name_len;
+ if (!cmp)
+ cmp = memcmp(name, (xs->base +
+ le16_to_cpu(entry->xe_name_offset)),
+ name_len);
+ if (cmp == 0)
+ break;
+ entry += 1;
+ }
+ xs->here = entry;
+
+ return cmp ? -ENODATA : 0;
+}
+
+static int ocfs2_xattr_get_value_outside(struct inode *inode,
+ struct ocfs2_xattr_value_root *xv,
+ void *buffer,
+ size_t len)
+{
+ u32 cpos, p_cluster, num_clusters, bpc, clusters;
+ u64 blkno;
+ int i, ret = 0;
+ size_t cplen, blocksize;
+ struct buffer_head *bh = NULL;
+ struct ocfs2_extent_list *el;
+
+ el = &xv->xr_list;
+ clusters = le32_to_cpu(xv->xr_clusters);
+ bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+ blocksize = inode->i_sb->s_blocksize;
+
+ cpos = 0;
+ while (cpos < clusters) {
+ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+ &num_clusters, el);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+ /* Copy ocfs2_xattr_value */
+ for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+ ret = ocfs2_read_block(inode, blkno, &bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ cplen = len >= blocksize ? blocksize : len;
+ memcpy(buffer, bh->b_data, cplen);
+ len -= cplen;
+ buffer += cplen;
+
+ brelse(bh);
+ bh = NULL;
+ if (len == 0)
+ break;
+ }
+ cpos += num_clusters;
+ }
+out:
+ return ret;
+}
+
+static int ocfs2_xattr_ibody_get(struct inode *inode,
+ int name_index,
+ const char *name,
+ void *buffer,
+ size_t buffer_size,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ struct ocfs2_xattr_value_root *xv;
+ size_t size;
+ int ret = 0;
+
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL))
+ return -ENODATA;
+
+ xs->end = (void *)di + inode->i_sb->s_blocksize;
+ xs->header = (struct ocfs2_xattr_header *)
+ (xs->end - le16_to_cpu(di->i_xattr_inline_size));
+ xs->base = (void *)xs->header;
+ xs->here = xs->header->xh_entries;
+
+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
+ if (ret)
+ return ret;
+ size = le64_to_cpu(xs->here->xe_value_size);
+ if (buffer) {
+ if (size > buffer_size)
+ return -ERANGE;
+ if (ocfs2_xattr_is_local(xs->here)) {
+ memcpy(buffer, (void *)xs->base +
+ le16_to_cpu(xs->here->xe_name_offset) +
+ OCFS2_XATTR_SIZE(xs->here->xe_name_len), size);
+ } else {
+ xv = (struct ocfs2_xattr_value_root *)
+ (xs->base + le16_to_cpu(
+ xs->here->xe_name_offset) +
+ OCFS2_XATTR_SIZE(xs->here->xe_name_len));
+ ret = ocfs2_xattr_get_value_outside(inode, xv,
+ buffer, size);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ }
+ }
+
+ return size;
+}
+
+static int ocfs2_xattr_block_get(struct inode *inode,
+ int name_index,
+ const char *name,
+ void *buffer,
+ size_t buffer_size,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ struct buffer_head *blk_bh = NULL;
+ struct ocfs2_xattr_block *xb;
+ struct ocfs2_xattr_value_root *xv;
+ size_t size;
+ int ret = -ENODATA, name_offset, name_len, block_off, i;
+
+ if (!di->i_xattr_loc)
+ return ret;
+
+ memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ /*Verify the signature of xattr block*/
+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ xs->xattr_bh = blk_bh;
+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ xs->header = &xb->xb_attrs.xb_header;
+ xs->base = (void *)xs->header;
+ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+ xs->here = xs->header->xh_entries;
+
+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
+ } else
+ ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+ name_index,
+ name, xs);
+
+ if (ret)
+ goto cleanup;
+ size = le64_to_cpu(xs->here->xe_value_size);
+ if (buffer) {
+ ret = -ERANGE;
+ if (size > buffer_size)
+ goto cleanup;
+
+ name_offset = le16_to_cpu(xs->here->xe_name_offset);
+ name_len = OCFS2_XATTR_SIZE(xs->here->xe_name_len);
+ i = xs->here - xs->header->xh_entries;
+
+ if (le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED) {
+ ret = ocfs2_xattr_bucket_get_name_value(inode,
+ xs->bucket.xh,
+ i,
+ &block_off,
+ &name_offset);
+ xs->base = xs->bucket.bhs[block_off]->b_data;
+ }
+ if (ocfs2_xattr_is_local(xs->here)) {
+ memcpy(buffer, (void *)xs->base +
+ name_offset + name_len, size);
+ } else {
+ xv = (struct ocfs2_xattr_value_root *)
+ (xs->base + name_offset + name_len);
+ ret = ocfs2_xattr_get_value_outside(inode, xv,
+ buffer, size);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto cleanup;
+ }
+ }
+ }
+ ret = size;
+cleanup:
+ for (i = 0; i < OCFS2_XATTR_MAX_BLOCKS_PER_BUCKET; i++)
+ brelse(xs->bucket.bhs[i]);
+ memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+ brelse(blk_bh);
+ return ret;
+}
+
+/* ocfs2_xattr_get()
+ *
+ * Copy an extended attribute into the buffer provided.
+ * Buffer is NULL to compute the size of buffer required.
+ */
+int ocfs2_xattr_get(struct inode *inode,
+ int name_index,
+ const char *name,
+ void *buffer,
+ size_t buffer_size)
+{
+ int ret;
+ struct ocfs2_dinode *di = NULL;
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_xattr_search xis = {
+ .not_found = -ENODATA,
+ };
+ struct ocfs2_xattr_search xbs = {
+ .not_found = -ENODATA,
+ };
+
+ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+ return -EOPNOTSUPP;
+
+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+ ret = -ENODATA;
+
+ ret = ocfs2_inode_lock(inode, &di_bh, 0);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ xis.inode_bh = xbs.inode_bh = di_bh;
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ down_read(&oi->ip_xattr_sem);
+ ret = ocfs2_xattr_ibody_get(inode, name_index, name, buffer,
+ buffer_size, &xis);
+ if (ret == -ENODATA)
+ ret = ocfs2_xattr_block_get(inode, name_index, name, buffer,
+ buffer_size, &xbs);
+ up_read(&oi->ip_xattr_sem);
+ ocfs2_inode_unlock(inode, 0);
+
+ brelse(di_bh);
+
+ return ret;
+}
+
+static int __ocfs2_xattr_set_value_outside(struct inode *inode,
+ struct ocfs2_xattr_value_root *xv,
+ const void *value,
+ int value_len)
+{
+ int ret = 0, i, cp_len, credits;
+ u16 blocksize = inode->i_sb->s_blocksize;
+ u32 p_cluster, num_clusters;
+ u32 cpos = 0, bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+ u32 clusters = ocfs2_clusters_for_bytes(inode->i_sb, value_len);
+ u64 blkno;
+ struct buffer_head *bh = NULL;
+ handle_t *handle;
+
+ BUG_ON(clusters > le32_to_cpu(xv->xr_clusters));
+
+ credits = clusters * bpc;
+ handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+
+ while (cpos < clusters) {
+ ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
+ &num_clusters, &xv->xr_list);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ blkno = ocfs2_clusters_to_blocks(inode->i_sb, p_cluster);
+
+ for (i = 0; i < num_clusters * bpc; i++, blkno++) {
+ ret = ocfs2_read_block(inode, blkno, &bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_journal_access(handle,
+ inode,
+ bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ cp_len = value_len > blocksize ? blocksize : value_len;
+ memcpy(bh->b_data, value, cp_len);
+ value_len -= cp_len;
+ value += cp_len;
+ if (cp_len < blocksize)
+ memset(bh->b_data + cp_len, 0,
+ blocksize - cp_len);
+
+ ret = ocfs2_journal_dirty(handle, bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ brelse(bh);
+ bh = NULL;
+
+ /*
+ * XXX: do we need to empty all the following
+ * blocks in this cluster?
+ */
+ if (!value_len)
+ break;
+ }
+ cpos += num_clusters;
+ }
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+ brelse(bh);
+
+ return ret;
+}
+
+static int ocfs2_xattr_cleanup(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ size_t offs)
+{
+ handle_t *handle = NULL;
+ int ret = 0;
+ size_t name_len = strlen(xi->name);
+ void *val = xs->base + offs;
+ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ /* Decrease xattr count */
+ le16_add_cpu(&xs->header->xh_count, -1);
+ /* Remove the xattr entry and tree root which has already be set*/
+ memset((void *)xs->here, 0, sizeof(struct ocfs2_xattr_entry));
+ memset(val, 0, size);
+
+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+ return ret;
+}
+
+static int ocfs2_xattr_update_entry(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ size_t offs)
+{
+ handle_t *handle = NULL;
+ int ret = 0;
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ xs->here->xe_name_offset = cpu_to_le16(offs);
+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+ if (xi->value_len <= OCFS2_XATTR_INLINE_SIZE)
+ ocfs2_xattr_set_local(xs->here, 1);
+ else
+ ocfs2_xattr_set_local(xs->here, 0);
+ ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+
+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_set_value_outside()
+ *
+ * Set large size value in B tree.
+ */
+static int ocfs2_xattr_set_value_outside(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ size_t offs)
+{
+ size_t name_len = strlen(xi->name);
+ void *val = xs->base + offs;
+ struct ocfs2_xattr_value_root *xv = NULL;
+ size_t size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+ int ret = 0;
+
+ memset(val, 0, size);
+ memcpy(val, xi->name, name_len);
+ xv = (struct ocfs2_xattr_value_root *)
+ (val + OCFS2_XATTR_SIZE(name_len));
+ xv->xr_clusters = 0;
+ xv->xr_last_eb_blk = 0;
+ xv->xr_list.l_tree_depth = 0;
+ xv->xr_list.l_count = cpu_to_le16(1);
+ xv->xr_list.l_next_free_rec = 0;
+
+ ret = ocfs2_xattr_value_truncate(inode, xs->xattr_bh, xv,
+ xi->value_len);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ ret = __ocfs2_xattr_set_value_outside(inode, xv, xi->value,
+ xi->value_len);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ ret = ocfs2_xattr_update_entry(inode, xi, xs, offs);
+ if (ret < 0)
+ mlog_errno(ret);
+
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_set_entry_local()
+ *
+ * Set, replace or remove extended attribute in local.
+ */
+static void ocfs2_xattr_set_entry_local(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ struct ocfs2_xattr_entry *last,
+ size_t min_offs)
+{
+ size_t name_len = strlen(xi->name);
+ int i;
+
+ if (xi->value && xs->not_found) {
+ /* Insert the new xattr entry. */
+ le16_add_cpu(&xs->header->xh_count, 1);
+ ocfs2_xattr_set_type(last, xi->name_index);
+ ocfs2_xattr_set_local(last, 1);
+ last->xe_name_len = name_len;
+ } else {
+ void *first_val;
+ void *val;
+ size_t offs, size;
+
+ first_val = xs->base + min_offs;
+ offs = le16_to_cpu(xs->here->xe_name_offset);
+ val = xs->base + offs;
+
+ if (le64_to_cpu(xs->here->xe_value_size) >
+ OCFS2_XATTR_INLINE_SIZE)
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_ROOT_SIZE;
+ else
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+
+ if (xi->value && size == OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(xi->value_len)) {
+ /* The old and the new value have the
+ same size. Just replace the value. */
+ ocfs2_xattr_set_local(xs->here, 1);
+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+ /* Clear value bytes. */
+ memset(val + OCFS2_XATTR_SIZE(name_len),
+ 0,
+ OCFS2_XATTR_SIZE(xi->value_len));
+ memcpy(val + OCFS2_XATTR_SIZE(name_len),
+ xi->value,
+ xi->value_len);
+ return;
+ }
+ /* Remove the old name+value. */
+ memmove(first_val + size, first_val, val - first_val);
+ memset(first_val, 0, size);
+ xs->here->xe_name_hash = 0;
+ xs->here->xe_name_offset = 0;
+ ocfs2_xattr_set_local(xs->here, 1);
+ xs->here->xe_value_size = 0;
+
+ min_offs += size;
+
+ /* Adjust all value offsets. */
+ last = xs->header->xh_entries;
+ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+ size_t o = le16_to_cpu(last->xe_name_offset);
+
+ if (o < offs)
+ last->xe_name_offset = cpu_to_le16(o + size);
+ last += 1;
+ }
+
+ if (!xi->value) {
+ /* Remove the old entry. */
+ last -= 1;
+ memmove(xs->here, xs->here + 1,
+ (void *)last - (void *)xs->here);
+ memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+ le16_add_cpu(&xs->header->xh_count, -1);
+ }
+ }
+ if (xi->value) {
+ /* Insert the new name+value. */
+ size_t size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(xi->value_len);
+ void *val = xs->base + min_offs - size;
+
+ xs->here->xe_name_offset = cpu_to_le16(min_offs - size);
+ memset(val, 0, size);
+ memcpy(val, xi->name, name_len);
+ memcpy(val + OCFS2_XATTR_SIZE(name_len),
+ xi->value,
+ xi->value_len);
+ xs->here->xe_value_size = cpu_to_le64(xi->value_len);
+ ocfs2_xattr_set_local(xs->here, 1);
+ ocfs2_xattr_hash_entry(inode, xs->header, xs->here);
+ }
+
+ return;
+}
+
+/*
+ * ocfs2_xattr_set_entry()
+ *
+ * Set extended attribute entry into inode or block.
+ *
+ * If extended attribute value size > OCFS2_XATTR_INLINE_SIZE,
+ * We first insert tree root(ocfs2_xattr_value_root) with set_entry_local(),
+ * then set value in B tree with set_value_outside().
+ */
+static int ocfs2_xattr_set_entry(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ int flag)
+{
+ struct ocfs2_xattr_entry *last;
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ size_t min_offs = xs->end - xs->base, name_len = strlen(xi->name);
+ size_t size_l = 0;
+ handle_t *handle = NULL;
+ int free, i, ret;
+ struct ocfs2_xattr_info xi_l = {
+ .name_index = xi->name_index,
+ .name = xi->name,
+ .value = xi->value,
+ .value_len = xi->value_len,
+ };
+
+ /* Compute min_offs, last and free space. */
+ last = xs->header->xh_entries;
+
+ for (i = 0 ; i < le16_to_cpu(xs->header->xh_count); i++) {
+ size_t offs = le16_to_cpu(last->xe_name_offset);
+ if (offs < min_offs)
+ min_offs = offs;
+ last += 1;
+ }
+
+ free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
+ if (free < 0)
+ return -EFAULT;
+
+ if (!xs->not_found) {
+ size_t size = 0;
+ if (ocfs2_xattr_is_local(xs->here))
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+ else
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_ROOT_SIZE;
+ free += (size + sizeof(struct ocfs2_xattr_entry));
+ }
+ /* Check free space in inode or block */
+ if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+ if (free < sizeof(struct ocfs2_xattr_entry) +
+ OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_ROOT_SIZE) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ size_l = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_ROOT_SIZE;
+ xi_l.value = (void *)&def_xv;
+ xi_l.value_len = OCFS2_XATTR_ROOT_SIZE;
+ } else if (xi->value) {
+ if (free < sizeof(struct ocfs2_xattr_entry) +
+ OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(xi->value_len)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ }
+
+ if (!xs->not_found) {
+ /* For existing extended attribute */
+ size_t size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(le64_to_cpu(xs->here->xe_value_size));
+ size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+ void *val = xs->base + offs;
+
+ if (ocfs2_xattr_is_local(xs->here) && size == size_l) {
+ /* Replace existing local xattr with tree root */
+ ret = ocfs2_xattr_set_value_outside(inode, xi, xs,
+ offs);
+ if (ret < 0)
+ mlog_errno(ret);
+ goto out;
+ } else if (!ocfs2_xattr_is_local(xs->here)) {
+ /* For existing xattr which has value outside */
+ struct ocfs2_xattr_value_root *xv = NULL;
+ xv = (struct ocfs2_xattr_value_root *)(val +
+ OCFS2_XATTR_SIZE(name_len));
+
+ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+ /*
+ * If new value need set outside also,
+ * first truncate old value to new value,
+ * then set new value with set_value_outside().
+ */
+ ret = ocfs2_xattr_value_truncate(inode,
+ xs->xattr_bh,
+ xv,
+ xi->value_len);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = __ocfs2_xattr_set_value_outside(inode,
+ xv,
+ xi->value,
+ xi->value_len);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_xattr_update_entry(inode,
+ xi,
+ xs,
+ offs);
+ if (ret < 0)
+ mlog_errno(ret);
+ goto out;
+ } else {
+ /*
+ * If new value need set in local,
+ * just trucate old value to zero.
+ */
+ ret = ocfs2_xattr_value_truncate(inode,
+ xs->xattr_bh,
+ xv,
+ 0);
+ if (ret < 0)
+ mlog_errno(ret);
+ }
+ }
+ }
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+ OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+ /* set extended attribute in external block. */
+ ret = ocfs2_extend_trans(handle,
+ OCFS2_INODE_UPDATE_CREDITS +
+ OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ }
+
+ /*
+ * Set value in local, include set tree root in local.
+ * This is the first step for value size >INLINE_SIZE.
+ */
+ ocfs2_xattr_set_entry_local(inode, &xi_l, xs, last, min_offs);
+
+ if (!(flag & OCFS2_INLINE_XATTR_FL)) {
+ ret = ocfs2_journal_dirty(handle, xs->xattr_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ }
+
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) &&
+ (flag & OCFS2_INLINE_XATTR_FL)) {
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ unsigned int xattrsize = osb->s_xattr_inline_size;
+
+ /*
+ * Adjust extent record count or inline data size
+ * to reserve space for extended attribute.
+ */
+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ struct ocfs2_inline_data *idata = &di->id2.i_data;
+ le16_add_cpu(&idata->id_count, -xattrsize);
+ } else if (!(ocfs2_inode_is_fast_symlink(inode))) {
+ struct ocfs2_extent_list *el = &di->id2.i_list;
+ le16_add_cpu(&el->l_count, -(xattrsize /
+ sizeof(struct ocfs2_extent_rec)));
+ }
+ di->i_xattr_inline_size = cpu_to_le16(xattrsize);
+ }
+ /* Update xattr flag */
+ spin_lock(&oi->ip_lock);
+ oi->ip_dyn_features |= flag;
+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+ spin_unlock(&oi->ip_lock);
+ /* Update inode ctime */
+ inode->i_ctime = CURRENT_TIME;
+ di->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
+ di->i_ctime_nsec = cpu_to_le32(inode->i_ctime.tv_nsec);
+
+ ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+
+ if (!ret && xi->value_len > OCFS2_XATTR_INLINE_SIZE) {
+ /*
+ * Set value outside in B tree.
+ * This is the second step for value size > INLINE_SIZE.
+ */
+ size_t offs = le16_to_cpu(xs->here->xe_name_offset);
+ ret = ocfs2_xattr_set_value_outside(inode, xi, xs, offs);
+ if (ret < 0) {
+ int ret2;
+
+ mlog_errno(ret);
+ /*
+ * If set value outside failed, we have to clean
+ * the junk tree root we have already set in local.
+ */
+ ret2 = ocfs2_xattr_cleanup(inode, xi, xs, offs);
+ if (ret2 < 0)
+ mlog_errno(ret2);
+ }
+ }
+out:
+ return ret;
+
+}
+
+static int ocfs2_remove_value_outside(struct inode*inode,
+ struct buffer_head *bh,
+ struct ocfs2_xattr_header *header)
+{
+ int ret = 0, i;
+
+ for (i = 0; i < le16_to_cpu(header->xh_count); i++) {
+ struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
+
+ if (!ocfs2_xattr_is_local(entry)) {
+ struct ocfs2_xattr_value_root *xv;
+ void *val;
+
+ val = (void *)header +
+ le16_to_cpu(entry->xe_name_offset);
+ xv = (struct ocfs2_xattr_value_root *)
+ (val + OCFS2_XATTR_SIZE(entry->xe_name_len));
+ ret = ocfs2_xattr_value_truncate(inode, bh, xv, 0);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int ocfs2_xattr_ibody_remove(struct inode *inode,
+ struct buffer_head *di_bh)
+{
+
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ struct ocfs2_xattr_header *header;
+ int ret;
+
+ header = (struct ocfs2_xattr_header *)
+ ((void *)di + inode->i_sb->s_blocksize -
+ le16_to_cpu(di->i_xattr_inline_size));
+
+ ret = ocfs2_remove_value_outside(inode, di_bh, header);
+
+ return ret;
+}
+
+static int ocfs2_xattr_block_remove(struct inode *inode,
+ struct buffer_head *blk_bh)
+{
+ struct ocfs2_xattr_block *xb;
+ int ret = 0;
+
+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ struct ocfs2_xattr_header *header = &(xb->xb_attrs.xb_header);
+ ret = ocfs2_remove_value_outside(inode, blk_bh, header);
+ } else
+ ret = ocfs2_delete_xattr_index_block(inode, blk_bh);
+
+ return ret;
+}
+
+static int ocfs2_xattr_free_block(struct inode *inode,
+ u64 block)
+{
+ struct inode *xb_alloc_inode;
+ struct buffer_head *xb_alloc_bh = NULL;
+ struct buffer_head *blk_bh = NULL;
+ struct ocfs2_xattr_block *xb;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ handle_t *handle;
+ int ret = 0;
+ u64 blk, bg_blkno;
+ u16 bit;
+
+ ret = ocfs2_read_block(inode, block, &blk_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*Verify the signature of xattr block*/
+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = ocfs2_xattr_block_remove(inode, blk_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+ blk = le64_to_cpu(xb->xb_blkno);
+ bit = le16_to_cpu(xb->xb_suballoc_bit);
+ bg_blkno = ocfs2_which_suballoc_group(blk, bit);
+
+ xb_alloc_inode = ocfs2_get_system_file_inode(osb,
+ EXTENT_ALLOC_SYSTEM_INODE,
+ le16_to_cpu(xb->xb_suballoc_slot));
+ if (!xb_alloc_inode) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+ mutex_lock(&xb_alloc_inode->i_mutex);
+
+ ret = ocfs2_inode_lock(xb_alloc_inode, &xb_alloc_bh, 1);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_mutex;
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_SUBALLOC_FREE);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_unlock;
+ }
+
+ ret = ocfs2_free_suballoc_bits(handle, xb_alloc_inode, xb_alloc_bh,
+ bit, bg_blkno, 1);
+ if (ret < 0)
+ mlog_errno(ret);
+
+ ocfs2_commit_trans(osb, handle);
+out_unlock:
+ ocfs2_inode_unlock(xb_alloc_inode, 1);
+ brelse(xb_alloc_bh);
+out_mutex:
+ mutex_unlock(&xb_alloc_inode->i_mutex);
+ iput(xb_alloc_inode);
+out:
+ brelse(blk_bh);
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_remove()
+ *
+ * Free extended attribute resources associated with this inode.
+ */
+int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+ handle_t *handle;
+ int ret;
+
+ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+ return 0;
+
+ if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
+ return 0;
+
+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+ ret = ocfs2_xattr_ibody_remove(inode, di_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ if (di->i_xattr_loc) {
+ ret = ocfs2_xattr_free_block(inode,
+ le64_to_cpu(di->i_xattr_loc));
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)),
+ OCFS2_INODE_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+ ret = ocfs2_journal_access(handle, inode, di_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ di->i_xattr_loc = 0;
+
+ spin_lock(&oi->ip_lock);
+ oi->ip_dyn_features &= ~(OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL);
+ di->i_dyn_features = cpu_to_le16(oi->ip_dyn_features);
+ spin_unlock(&oi->ip_lock);
+
+ ret = ocfs2_journal_dirty(handle, di_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+ return ret;
+}
+
+static int ocfs2_xattr_has_space_inline(struct inode *inode,
+ struct ocfs2_dinode *di)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ unsigned int xattrsize = OCFS2_SB(inode->i_sb)->s_xattr_inline_size;
+ int free;
+
+ if (xattrsize < OCFS2_MIN_XATTR_INLINE_SIZE)
+ return 0;
+
+ if (oi->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
+ struct ocfs2_inline_data *idata = &di->id2.i_data;
+ free = le16_to_cpu(idata->id_count) - le64_to_cpu(di->i_size);
+ } else if (ocfs2_inode_is_fast_symlink(inode)) {
+ free = ocfs2_fast_symlink_chars(inode->i_sb) -
+ le64_to_cpu(di->i_size);
+ } else {
+ struct ocfs2_extent_list *el = &di->id2.i_list;
+ free = (le16_to_cpu(el->l_count) -
+ le16_to_cpu(el->l_next_free_rec)) *
+ sizeof(struct ocfs2_extent_rec);
+ }
+ if (free >= xattrsize)
+ return 1;
+
+ return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_find()
+ *
+ * Find extended attribute in inode block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_ibody_find(struct inode *inode,
+ int name_index,
+ const char *name,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ int ret;
+ int has_space = 0;
+
+ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+ return 0;
+
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+ down_read(&oi->ip_alloc_sem);
+ has_space = ocfs2_xattr_has_space_inline(inode, di);
+ up_read(&oi->ip_alloc_sem);
+ if (!has_space)
+ return 0;
+ }
+
+ xs->xattr_bh = xs->inode_bh;
+ xs->end = (void *)di + inode->i_sb->s_blocksize;
+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)
+ xs->header = (struct ocfs2_xattr_header *)
+ (xs->end - le16_to_cpu(di->i_xattr_inline_size));
+ else
+ xs->header = (struct ocfs2_xattr_header *)
+ (xs->end - OCFS2_SB(inode->i_sb)->s_xattr_inline_size);
+ xs->base = (void *)xs->header;
+ xs->here = xs->header->xh_entries;
+
+ /* Find the named attribute. */
+ if (oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL) {
+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
+ if (ret && ret != -ENODATA)
+ return ret;
+ xs->not_found = ret;
+ }
+
+ return 0;
+}
+
+/*
+ * ocfs2_xattr_ibody_set()
+ *
+ * Set, replace or remove an extended attribute into inode block.
+ *
+ */
+static int ocfs2_xattr_ibody_set(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ int ret;
+
+ if (inode->i_sb->s_blocksize == OCFS2_MIN_BLOCKSIZE)
+ return -ENOSPC;
+
+ down_write(&oi->ip_alloc_sem);
+ if (!(oi->ip_dyn_features & OCFS2_INLINE_XATTR_FL)) {
+ if (!ocfs2_xattr_has_space_inline(inode, di)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+ }
+
+ ret = ocfs2_xattr_set_entry(inode, xi, xs,
+ (OCFS2_INLINE_XATTR_FL | OCFS2_HAS_XATTR_FL));
+out:
+ up_write(&oi->ip_alloc_sem);
+
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_block_find()
+ *
+ * Find extended attribute in external block and
+ * fill search info into struct ocfs2_xattr_search.
+ */
+static int ocfs2_xattr_block_find(struct inode *inode,
+ int name_index,
+ const char *name,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ struct buffer_head *blk_bh = NULL;
+ struct ocfs2_xattr_block *xb;
+ int ret = 0;
+
+ if (!di->i_xattr_loc)
+ return ret;
+
+ ret = ocfs2_read_block(inode, le64_to_cpu(di->i_xattr_loc), &blk_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ /*Verify the signature of xattr block*/
+ if (memcmp((void *)blk_bh->b_data, OCFS2_XATTR_BLOCK_SIGNATURE,
+ strlen(OCFS2_XATTR_BLOCK_SIGNATURE))) {
+ ret = -EFAULT;
+ goto cleanup;
+ }
+
+ xs->xattr_bh = blk_bh;
+ xb = (struct ocfs2_xattr_block *)blk_bh->b_data;
+
+ if (!(le16_to_cpu(xb->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ xs->header = &xb->xb_attrs.xb_header;
+ xs->base = (void *)xs->header;
+ xs->end = (void *)(blk_bh->b_data) + blk_bh->b_size;
+ xs->here = xs->header->xh_entries;
+
+ ret = ocfs2_xattr_find_entry(name_index, name, xs);
+ } else
+ ret = ocfs2_xattr_index_block_find(inode, blk_bh,
+ name_index,
+ name, xs);
+
+ if (ret && ret != -ENODATA) {
+ xs->xattr_bh = NULL;
+ goto cleanup;
+ }
+ xs->not_found = ret;
+ return 0;
+cleanup:
+ brelse(blk_bh);
+
+ return ret;
+}
+
+/*
+ * When all the xattrs are deleted from index btree, the ocfs2_xattr_tree
+ * will be erased and ocfs2_xattr_block will have its ocfs2_xattr_header
+ * re-initialized.
+ */
+static int ocfs2_restore_xattr_block(struct inode *inode,
+ struct ocfs2_xattr_search *xs)
+{
+ int ret;
+ handle_t *handle;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+ struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+ u16 xb_flags = le16_to_cpu(xb->xb_flags);
+
+ BUG_ON(!(xb_flags & OCFS2_XATTR_INDEXED) ||
+ le16_to_cpu(el->l_next_free_rec) != 0);
+
+ handle = ocfs2_start_trans(osb, OCFS2_XATTR_BLOCK_UPDATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, xs->xattr_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+ offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+ xb->xb_flags = cpu_to_le16(xb_flags & ~OCFS2_XATTR_INDEXED);
+
+ ocfs2_journal_dirty(handle, xs->xattr_bh);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_block_set()
+ *
+ * Set, replace or remove an extended attribute into external block.
+ *
+ */
+static int ocfs2_xattr_block_set(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs)
+{
+ struct buffer_head *new_bh = NULL;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_dinode *di = (struct ocfs2_dinode *)xs->inode_bh->b_data;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ handle_t *handle = NULL;
+ struct ocfs2_xattr_block *xblk = NULL;
+ u16 suballoc_bit_start;
+ u32 num_got;
+ u64 first_blkno;
+ int ret;
+
+ if (!xs->xattr_bh) {
+ /*
+ * Alloc one external block for extended attribute
+ * outside of inode.
+ */
+ ret = ocfs2_reserve_new_metadata_blocks(osb, 1, &meta_ac);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ handle = ocfs2_start_trans(osb,
+ OCFS2_XATTR_BLOCK_CREATE_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out;
+ }
+ ret = ocfs2_journal_access(handle, inode, xs->inode_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_claim_metadata(osb, handle, meta_ac, 1,
+ &suballoc_bit_start, &num_got,
+ &first_blkno);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ new_bh = sb_getblk(inode->i_sb, first_blkno);
+ ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+ ret = ocfs2_journal_access(handle, inode, new_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /* Initialize ocfs2_xattr_block */
+ xs->xattr_bh = new_bh;
+ xblk = (struct ocfs2_xattr_block *)new_bh->b_data;
+ memset(xblk, 0, inode->i_sb->s_blocksize);
+ strcpy((void *)xblk, OCFS2_XATTR_BLOCK_SIGNATURE);
+ xblk->xb_suballoc_slot = cpu_to_le16(osb->slot_num);
+ xblk->xb_suballoc_bit = cpu_to_le16(suballoc_bit_start);
+ xblk->xb_fs_generation = cpu_to_le32(osb->fs_generation);
+ xblk->xb_blkno = cpu_to_le64(first_blkno);
+
+ xs->header = &xblk->xb_attrs.xb_header;
+ xs->base = (void *)xs->header;
+ xs->end = (void *)xblk + inode->i_sb->s_blocksize;
+ xs->here = xs->header->xh_entries;
+
+
+ ret = ocfs2_journal_dirty(handle, new_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ di->i_xattr_loc = cpu_to_le64(first_blkno);
+ ret = ocfs2_journal_dirty(handle, xs->inode_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+ if (ret < 0)
+ return ret;
+ } else
+ xblk = (struct ocfs2_xattr_block *)xs->xattr_bh->b_data;
+
+ if (!(le16_to_cpu(xblk->xb_flags) & OCFS2_XATTR_INDEXED)) {
+ /* Set extended attribute into external block */
+ ret = ocfs2_xattr_set_entry(inode, xi, xs, OCFS2_HAS_XATTR_FL);
+ if (!ret || ret != -ENOSPC)
+ goto end;
+
+ ret = ocfs2_xattr_create_index_block(inode, xs);
+ if (ret)
+ goto end;
+ }
+
+ ret = ocfs2_xattr_set_entry_index_block(inode, xi, xs);
+ if (!ret && xblk->xb_attrs.xb_root.xt_list.l_next_free_rec == 0)
+ ret = ocfs2_restore_xattr_block(inode, xs);
+
+end:
+
+ return ret;
+}
+
+/*
+ * ocfs2_xattr_set()
+ *
+ * Set, replace or remove an extended attribute for this inode.
+ * value is NULL to remove an existing extended attribute, else either
+ * create or replace an extended attribute.
+ */
+int ocfs2_xattr_set(struct inode *inode,
+ int name_index,
+ const char *name,
+ const void *value,
+ size_t value_len,
+ int flags)
+{
+ struct buffer_head *di_bh = NULL;
+ struct ocfs2_dinode *di;
+ int ret;
+ u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+ struct ocfs2_xattr_info xi = {
+ .name_index = name_index,
+ .name = name,
+ .value = value,
+ .value_len = value_len,
+ };
+
+ struct ocfs2_xattr_search xis = {
+ .not_found = -ENODATA,
+ };
+
+ struct ocfs2_xattr_search xbs = {
+ .not_found = -ENODATA,
+ };
+
+ if (!ocfs2_supports_xattr(OCFS2_SB(inode->i_sb)))
+ return -EOPNOTSUPP;
+
+ ret = ocfs2_inode_lock(inode, &di_bh, 1);
+ if (ret < 0) {
+ mlog_errno(ret);
+ return ret;
+ }
+ xis.inode_bh = xbs.inode_bh = di_bh;
+ di = (struct ocfs2_dinode *)di_bh->b_data;
+
+ down_write(&OCFS2_I(inode)->ip_xattr_sem);
+ /*
+ * Scan inode and external block to find the same name
+ * extended attribute and collect search infomation.
+ */
+ ret = ocfs2_xattr_ibody_find(inode, name_index, name, &xis);
+ if (ret)
+ goto cleanup;
+ if (xis.not_found) {
+ ret = ocfs2_xattr_block_find(inode, name_index, name, &xbs);
+ if (ret)
+ goto cleanup;
+ }
+
+ if (xis.not_found && xbs.not_found) {
+ ret = -ENODATA;
+ if (flags & XATTR_REPLACE)
+ goto cleanup;
+ ret = 0;
+ if (!value)
+ goto cleanup;
+ } else {
+ ret = -EEXIST;
+ if (flags & XATTR_CREATE)
+ goto cleanup;
+ }
+
+ if (!value) {
+ /* Remove existing extended attribute */
+ if (!xis.not_found)
+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+ else if (!xbs.not_found)
+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+ } else {
+ /* We always try to set extended attribute into inode first*/
+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+ if (!ret && !xbs.not_found) {
+ /*
+ * If succeed and that extended attribute existing in
+ * external block, then we will remove it.
+ */
+ xi.value = NULL;
+ xi.value_len = 0;
+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+ } else if (ret == -ENOSPC) {
+ if (di->i_xattr_loc && !xbs.xattr_bh) {
+ ret = ocfs2_xattr_block_find(inode, name_index,
+ name, &xbs);
+ if (ret)
+ goto cleanup;
+ }
+ /*
+ * If no space in inode, we will set extended attribute
+ * into external block.
+ */
+ ret = ocfs2_xattr_block_set(inode, &xi, &xbs);
+ if (ret)
+ goto cleanup;
+ if (!xis.not_found) {
+ /*
+ * If succeed and that extended attribute
+ * existing in inode, we will remove it.
+ */
+ xi.value = NULL;
+ xi.value_len = 0;
+ ret = ocfs2_xattr_ibody_set(inode, &xi, &xis);
+ }
+ }
+ }
+cleanup:
+ up_write(&OCFS2_I(inode)->ip_xattr_sem);
+ ocfs2_inode_unlock(inode, 1);
+ brelse(di_bh);
+ brelse(xbs.xattr_bh);
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(xbs.bucket.bhs[i]);
+
+ return ret;
+}
+
+/*
+ * Find the xattr extent rec which may contains name_hash.
+ * e_cpos will be the first name hash of the xattr rec.
+ * el must be the ocfs2_xattr_header.xb_attrs.xb_root.xt_list.
+ */
+static int ocfs2_xattr_get_rec(struct inode *inode,
+ u32 name_hash,
+ u64 *p_blkno,
+ u32 *e_cpos,
+ u32 *num_clusters,
+ struct ocfs2_extent_list *el)
+{
+ int ret = 0, i;
+ struct buffer_head *eb_bh = NULL;
+ struct ocfs2_extent_block *eb;
+ struct ocfs2_extent_rec *rec = NULL;
+ u64 e_blkno = 0;
+
+ if (el->l_tree_depth) {
+ ret = ocfs2_find_leaf(inode, el, name_hash, &eb_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ eb = (struct ocfs2_extent_block *) eb_bh->b_data;
+ el = &eb->h_list;
+
+ if (el->l_tree_depth) {
+ ocfs2_error(inode->i_sb,
+ "Inode %lu has non zero tree depth in "
+ "xattr tree block %llu\n", inode->i_ino,
+ (unsigned long long)eb_bh->b_blocknr);
+ ret = -EROFS;
+ goto out;
+ }
+ }
+
+ for (i = le16_to_cpu(el->l_next_free_rec) - 1; i >= 0; i--) {
+ rec = &el->l_recs[i];
+
+ if (le32_to_cpu(rec->e_cpos) <= name_hash) {
+ e_blkno = le64_to_cpu(rec->e_blkno);
+ break;
+ }
+ }
+
+ if (!e_blkno) {
+ ocfs2_error(inode->i_sb, "Inode %lu has bad extent "
+ "record (%u, %u, 0) in xattr", inode->i_ino,
+ le32_to_cpu(rec->e_cpos),
+ ocfs2_rec_clusters(el, rec));
+ ret = -EROFS;
+ goto out;
+ }
+
+ *p_blkno = le64_to_cpu(rec->e_blkno);
+ *num_clusters = le16_to_cpu(rec->e_leaf_clusters);
+ if (e_cpos)
+ *e_cpos = le32_to_cpu(rec->e_cpos);
+out:
+ brelse(eb_bh);
+ return ret;
+}
+
+typedef int (xattr_bucket_func)(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket,
+ void *para);
+
+static int ocfs2_find_xe_in_bucket(struct inode *inode,
+ struct buffer_head *header_bh,
+ int name_index,
+ const char *name,
+ u32 name_hash,
+ u16 *xe_index,
+ int *found)
+{
+ int i, ret = 0, cmp = 1, block_off, new_offset;
+ struct ocfs2_xattr_header *xh =
+ (struct ocfs2_xattr_header *)header_bh->b_data;
+ size_t name_len = strlen(name);
+ struct ocfs2_xattr_entry *xe = NULL;
+ struct buffer_head *name_bh = NULL;
+ char *xe_name;
+
+ /*
+ * We don't use binary search in the bucket because there
+ * may be multiple entries with the same name hash.
+ */
+ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+ xe = &xh->xh_entries[i];
+
+ if (name_hash > le32_to_cpu(xe->xe_name_hash))
+ continue;
+ else if (name_hash < le32_to_cpu(xe->xe_name_hash))
+ break;
+
+ cmp = name_index - ocfs2_xattr_get_type(xe);
+ if (!cmp)
+ cmp = name_len - xe->xe_name_len;
+ if (cmp)
+ continue;
+
+ ret = ocfs2_xattr_bucket_get_name_value(inode,
+ xh,
+ i,
+ &block_off,
+ &new_offset);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+
+ ret = ocfs2_read_block(inode, header_bh->b_blocknr + block_off,
+ &name_bh);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+ xe_name = name_bh->b_data + new_offset;
+
+ cmp = memcmp(name, xe_name, name_len);
+ brelse(name_bh);
+ name_bh = NULL;
+
+ if (cmp == 0) {
+ *xe_index = i;
+ *found = 1;
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Find the specified xattr entry in a series of buckets.
+ * This series start from p_blkno and last for num_clusters.
+ * The ocfs2_xattr_header.xh_num_buckets of the first bucket contains
+ * the num of the valid buckets.
+ *
+ * Return the buffer_head this xattr should reside in. And if the xattr's
+ * hash is in the gap of 2 buckets, return the lower bucket.
+ */
+static int ocfs2_xattr_bucket_find(struct inode *inode,
+ int name_index,
+ const char *name,
+ u32 name_hash,
+ u64 p_blkno,
+ u32 first_hash,
+ u32 num_clusters,
+ struct ocfs2_xattr_search *xs)
+{
+ int ret, found = 0;
+ struct buffer_head *bh = NULL;
+ struct buffer_head *lower_bh = NULL;
+ struct ocfs2_xattr_header *xh = NULL;
+ struct ocfs2_xattr_entry *xe = NULL;
+ u16 index = 0;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ int low_bucket = 0, bucket, high_bucket;
+ u32 last_hash;
+ u64 blkno;
+
+ ret = ocfs2_read_block(inode, p_blkno, &bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xh = (struct ocfs2_xattr_header *)bh->b_data;
+ high_bucket = le16_to_cpu(xh->xh_num_buckets) - 1;
+
+ while (low_bucket <= high_bucket) {
+ brelse(bh);
+ bh = NULL;
+ bucket = (low_bucket + high_bucket) / 2;
+
+ blkno = p_blkno + bucket * blk_per_bucket;
+
+ ret = ocfs2_read_block(inode, blkno, &bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xh = (struct ocfs2_xattr_header *)bh->b_data;
+ xe = &xh->xh_entries[0];
+ if (name_hash < le32_to_cpu(xe->xe_name_hash)) {
+ high_bucket = bucket - 1;
+ continue;
+ }
+
+ /*
+ * Check whether the hash of the last entry in our
+ * bucket is larger than the search one. for an empty
+ * bucket, the last one is also the first one.
+ */
+ if (xh->xh_count)
+ xe = &xh->xh_entries[le16_to_cpu(xh->xh_count) - 1];
+
+ last_hash = le32_to_cpu(xe->xe_name_hash);
+
+ /* record lower_bh which may be the insert place. */
+ brelse(lower_bh);
+ lower_bh = bh;
+ bh = NULL;
+
+ if (name_hash > le32_to_cpu(xe->xe_name_hash)) {
+ low_bucket = bucket + 1;
+ continue;
+ }
+
+ /* the searched xattr should reside in this bucket if exists. */
+ ret = ocfs2_find_xe_in_bucket(inode, lower_bh,
+ name_index, name, name_hash,
+ &index, &found);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ break;
+ }
+
+ /*
+ * Record the bucket we have found.
+ * When the xattr's hash value is in the gap of 2 buckets, we will
+ * always set it to the previous bucket.
+ */
+ if (!lower_bh) {
+ /*
+ * We can't find any bucket whose first name_hash is less
+ * than the find name_hash.
+ */
+ BUG_ON(bh->b_blocknr != p_blkno);
+ lower_bh = bh;
+ bh = NULL;
+ }
+ xs->bucket.bhs[0] = lower_bh;
+ xs->bucket.xh = (struct ocfs2_xattr_header *)
+ xs->bucket.bhs[0]->b_data;
+ lower_bh = NULL;
+
+ xs->header = xs->bucket.xh;
+ xs->base = xs->bucket.bhs[0]->b_data;
+ xs->end = xs->base + inode->i_sb->s_blocksize;
+
+ if (found) {
+ /*
+ * If we have found the xattr enty, read all the blocks in
+ * this bucket.
+ */
+ ret = ocfs2_read_blocks(inode, xs->bucket.bhs[0]->b_blocknr + 1,
+ blk_per_bucket - 1, &xs->bucket.bhs[1],
+ 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xs->here = &xs->header->xh_entries[index];
+ mlog(0, "find xattr %s in bucket %llu, entry = %u\n", name,
+ (unsigned long long)xs->bucket.bhs[0]->b_blocknr, index);
+ } else
+ ret = -ENODATA;
+
+out:
+ brelse(bh);
+ brelse(lower_bh);
+ return ret;
+}
+
+static int ocfs2_xattr_index_block_find(struct inode *inode,
+ struct buffer_head *root_bh,
+ int name_index,
+ const char *name,
+ struct ocfs2_xattr_search *xs)
+{
+ int ret;
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)root_bh->b_data;
+ struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+ struct ocfs2_extent_list *el = &xb_root->xt_list;
+ u64 p_blkno = 0;
+ u32 first_hash, num_clusters = 0;
+ u32 name_hash = ocfs2_xattr_name_hash(inode, name, strlen(name));
+
+ if (le16_to_cpu(el->l_next_free_rec) == 0)
+ return -ENODATA;
+
+ mlog(0, "find xattr %s, hash = %u, index = %d in xattr tree\n",
+ name, name_hash, name_index);
+
+ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &first_hash,
+ &num_clusters, el);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ BUG_ON(p_blkno == 0 || num_clusters == 0 || first_hash > name_hash);
+
+ mlog(0, "find xattr extent rec %u clusters from %llu, the first hash "
+ "in the rec is %u\n", num_clusters, p_blkno, first_hash);
+
+ ret = ocfs2_xattr_bucket_find(inode, name_index, name, name_hash,
+ p_blkno, first_hash, num_clusters, xs);
+
+out:
+ return ret;
+}
+
+static int ocfs2_iterate_xattr_buckets(struct inode *inode,
+ u64 blkno,
+ u32 clusters,
+ xattr_bucket_func *func,
+ void *para)
+{
+ int i, j, ret = 0;
+ int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ u32 bpc = ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb));
+ u32 num_buckets = clusters * bpc;
+ struct ocfs2_xattr_bucket bucket;
+
+ memset(&bucket, 0, sizeof(bucket));
+
+ mlog(0, "iterating xattr buckets in %u clusters starting from %llu\n",
+ clusters, blkno);
+
+ for (i = 0; i < num_buckets; i++, blkno += blk_per_bucket) {
+ ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket,
+ bucket.bhs, 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ bucket.xh = (struct ocfs2_xattr_header *)bucket.bhs[0]->b_data;
+ /*
+ * The real bucket num in this series of blocks is stored
+ * in the 1st bucket.
+ */
+ if (i == 0)
+ num_buckets = le16_to_cpu(bucket.xh->xh_num_buckets);
+
+ mlog(0, "iterating xattr bucket %llu, first hash %u\n", blkno,
+ le32_to_cpu(bucket.xh->xh_entries[0].xe_name_hash));
+ if (func) {
+ ret = func(inode, &bucket, para);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+ }
+
+ for (j = 0; j < blk_per_bucket; j++)
+ brelse(bucket.bhs[j]);
+ memset(&bucket, 0, sizeof(bucket));
+ }
+
+out:
+ for (j = 0; j < blk_per_bucket; j++)
+ brelse(bucket.bhs[j]);
+
+ return ret;
+}
+
+struct ocfs2_xattr_tree_list {
+ char *buffer;
+ size_t buffer_size;
+ size_t result;
+};
+
+static int ocfs2_xattr_bucket_get_name_value(struct inode *inode,
+ struct ocfs2_xattr_header *xh,
+ int index,
+ int *block_off,
+ int *new_offset)
+{
+ u16 name_offset;
+
+ if (index < 0 || index >= le16_to_cpu(xh->xh_count))
+ return -EINVAL;
+
+ name_offset = le16_to_cpu(xh->xh_entries[index].xe_name_offset);
+
+ *block_off = name_offset >> inode->i_sb->s_blocksize_bits;
+ *new_offset = name_offset % inode->i_sb->s_blocksize;
+
+ return 0;
+}
+
+static int ocfs2_list_xattr_bucket(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket,
+ void *para)
+{
+ int ret = 0, type;
+ struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
+ int i, block_off, new_offset;
+ const char *prefix, *name;
+
+ for (i = 0 ; i < le16_to_cpu(bucket->xh->xh_count); i++) {
+ struct ocfs2_xattr_entry *entry = &bucket->xh->xh_entries[i];
+ type = ocfs2_xattr_get_type(entry);
+ prefix = ocfs2_xattr_prefix(type);
+
+ if (prefix) {
+ ret = ocfs2_xattr_bucket_get_name_value(inode,
+ bucket->xh,
+ i,
+ &block_off,
+ &new_offset);
+ if (ret)
+ break;
+
+ name = (const char *)bucket->bhs[block_off]->b_data +
+ new_offset;
+ ret = ocfs2_xattr_list_entry(xl->buffer,
+ xl->buffer_size,
+ &xl->result,
+ prefix, name,
+ entry->xe_name_len);
+ if (ret)
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int ocfs2_xattr_tree_list_index_block(struct inode *inode,
+ struct ocfs2_xattr_tree_root *xt,
+ char *buffer,
+ size_t buffer_size)
+{
+ struct ocfs2_extent_list *el = &xt->xt_list;
+ int ret = 0;
+ u32 name_hash = UINT_MAX, e_cpos = 0, num_clusters = 0;
+ u64 p_blkno = 0;
+ struct ocfs2_xattr_tree_list xl = {
+ .buffer = buffer,
+ .buffer_size = buffer_size,
+ .result = 0,
+ };
+
+ if (le16_to_cpu(el->l_next_free_rec) == 0)
+ return 0;
+
+ while (name_hash > 0) {
+ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+ &e_cpos, &num_clusters, el);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+ ocfs2_list_xattr_bucket,
+ &xl);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (e_cpos == 0)
+ break;
+
+ name_hash = e_cpos - 1;
+ }
+
+ ret = xl.result;
+out:
+ return ret;
+}
+
+static int cmp_xe(const void *a, const void *b)
+{
+ const struct ocfs2_xattr_entry *l = a, *r = b;
+ u32 l_hash = le32_to_cpu(l->xe_name_hash);
+ u32 r_hash = le32_to_cpu(r->xe_name_hash);
+
+ if (l_hash > r_hash)
+ return 1;
+ if (l_hash < r_hash)
+ return -1;
+ return 0;
+}
+
+static void swap_xe(void *a, void *b, int size)
+{
+ struct ocfs2_xattr_entry *l = a, *r = b, tmp;
+
+ tmp = *l;
+ memcpy(l, r, sizeof(struct ocfs2_xattr_entry));
+ memcpy(r, &tmp, sizeof(struct ocfs2_xattr_entry));
+}
+
+/*
+ * When the ocfs2_xattr_block is filled up, new bucket will be created
+ * and all the xattr entries will be moved to the new bucket.
+ * Note: we need to sort the entries since they are not saved in order
+ * in the ocfs2_xattr_block.
+ */
+static void ocfs2_cp_xattr_block_to_bucket(struct inode *inode,
+ struct buffer_head *xb_bh,
+ struct buffer_head *xh_bh,
+ struct buffer_head *data_bh)
+{
+ int i, blocksize = inode->i_sb->s_blocksize;
+ u16 offset, size, off_change;
+ struct ocfs2_xattr_entry *xe;
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)xb_bh->b_data;
+ struct ocfs2_xattr_header *xb_xh = &xb->xb_attrs.xb_header;
+ struct ocfs2_xattr_header *xh =
+ (struct ocfs2_xattr_header *)xh_bh->b_data;
+ u16 count = le16_to_cpu(xb_xh->xh_count);
+ char *target = xh_bh->b_data, *src = xb_bh->b_data;
+
+ mlog(0, "cp xattr from block %llu to bucket %llu\n",
+ (unsigned long long)xb_bh->b_blocknr,
+ (unsigned long long)xh_bh->b_blocknr);
+
+ memset(xh_bh->b_data, 0, blocksize);
+ if (data_bh)
+ memset(data_bh->b_data, 0, blocksize);
+ /*
+ * Since the xe_name_offset is based on ocfs2_xattr_header,
+ * there is a offset change corresponding to the change of
+ * ocfs2_xattr_header's position.
+ */
+ off_change = offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+ xe = &xb_xh->xh_entries[count - 1];
+ offset = le16_to_cpu(xe->xe_name_offset) + off_change;
+ size = blocksize - offset;
+
+ /* copy all the names and values. */
+ if (data_bh)
+ target = data_bh->b_data;
+ memcpy(target + offset, src + offset, size);
+
+ /* Init new header now. */
+ xh->xh_count = xb_xh->xh_count;
+ xh->xh_num_buckets = cpu_to_le16(1);
+ xh->xh_name_value_len = cpu_to_le16(size);
+ xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE - size);
+
+ /* copy all the entries. */
+ target = xh_bh->b_data;
+ offset = offsetof(struct ocfs2_xattr_header, xh_entries);
+ size = count * sizeof(struct ocfs2_xattr_entry);
+ memcpy(target + offset, (char *)xb_xh + offset, size);
+
+ /* Change the xe offset for all the xe because of the move. */
+ off_change = OCFS2_XATTR_BUCKET_SIZE - blocksize +
+ offsetof(struct ocfs2_xattr_block, xb_attrs.xb_header);
+ for (i = 0; i < count; i++)
+ le16_add_cpu(&xh->xh_entries[i].xe_name_offset, off_change);
+
+ mlog(0, "copy entry: start = %u, size = %u, offset_change = %u\n",
+ offset, size, off_change);
+
+ sort(target + offset, count, sizeof(struct ocfs2_xattr_entry),
+ cmp_xe, swap_xe);
+}
+
+/*
+ * After we move xattr from block to index btree, we have to
+ * update ocfs2_xattr_search to the new xe and base.
+ *
+ * When the entry is in xattr block, xattr_bh indicates the storage place.
+ * While if the entry is in index b-tree, "bucket" indicates the
+ * real place of the xattr.
+ */
+static int ocfs2_xattr_update_xattr_search(struct inode *inode,
+ struct ocfs2_xattr_search *xs,
+ struct buffer_head *old_bh,
+ struct buffer_head *new_bh)
+{
+ int ret = 0;
+ char *buf = old_bh->b_data;
+ struct ocfs2_xattr_block *old_xb = (struct ocfs2_xattr_block *)buf;
+ struct ocfs2_xattr_header *old_xh = &old_xb->xb_attrs.xb_header;
+ int i, blocksize = inode->i_sb->s_blocksize;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+ xs->bucket.bhs[0] = new_bh;
+ get_bh(new_bh);
+ xs->bucket.xh = (struct ocfs2_xattr_header *)xs->bucket.bhs[0]->b_data;
+ xs->header = xs->bucket.xh;
+
+ xs->base = new_bh->b_data;
+ xs->end = xs->base + inode->i_sb->s_blocksize;
+
+ if (!xs->not_found) {
+ if (OCFS2_XATTR_BUCKET_SIZE != blocksize) {
+ ret = ocfs2_read_blocks(inode,
+ xs->bucket.bhs[0]->b_blocknr + 1,
+ blk_per_bucket - 1, &xs->bucket.bhs[1],
+ 0);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ i = xs->here - old_xh->xh_entries;
+ xs->here = &xs->header->xh_entries[i];
+ }
+ }
+
+ return ret;
+}
+
+static int ocfs2_xattr_create_index_block(struct inode *inode,
+ struct ocfs2_xattr_search *xs)
+{
+ int ret, credits = OCFS2_SUBALLOC_ALLOC;
+ u32 bit_off, len;
+ u64 blkno;
+ handle_t *handle;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_inode_info *oi = OCFS2_I(inode);
+ struct ocfs2_alloc_context *data_ac;
+ struct buffer_head *xh_bh = NULL, *data_bh = NULL;
+ struct buffer_head *xb_bh = xs->xattr_bh;
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)xb_bh->b_data;
+ struct ocfs2_xattr_tree_root *xr;
+ u16 xb_flags = le16_to_cpu(xb->xb_flags);
+ u16 bpb = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+ mlog(0, "create xattr index block for %llu\n",
+ (unsigned long long)xb_bh->b_blocknr);
+
+ BUG_ON(xb_flags & OCFS2_XATTR_INDEXED);
+
+ ret = ocfs2_reserve_clusters(osb, 1, &data_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ /*
+ * XXX:
+ * We can use this lock for now, and maybe move to a dedicated mutex
+ * if performance becomes a problem later.
+ */
+ down_write(&oi->ip_alloc_sem);
+
+ /*
+ * 3 more credits, one for xattr block update, one for the 1st block
+ * of the new xattr bucket and one for the value/data.
+ */
+ credits += 3;
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ goto out_sem;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, xb_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off, &len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /*
+ * The bucket may spread in many blocks, and
+ * we will only touch the 1st block and the last block
+ * in the whole bucket(one for entry and one for data).
+ */
+ blkno = ocfs2_clusters_to_blocks(inode->i_sb, bit_off);
+
+ mlog(0, "allocate 1 cluster from %llu to xattr block\n", blkno);
+
+ xh_bh = sb_getblk(inode->i_sb, blkno);
+ if (!xh_bh) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ocfs2_set_new_buffer_uptodate(inode, xh_bh);
+
+ ret = ocfs2_journal_access(handle, inode, xh_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ if (bpb > 1) {
+ data_bh = sb_getblk(inode->i_sb, blkno + bpb - 1);
+ if (!data_bh) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ocfs2_set_new_buffer_uptodate(inode, data_bh);
+
+ ret = ocfs2_journal_access(handle, inode, data_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+ }
+
+ ocfs2_cp_xattr_block_to_bucket(inode, xb_bh, xh_bh, data_bh);
+
+ ocfs2_journal_dirty(handle, xh_bh);
+ if (data_bh)
+ ocfs2_journal_dirty(handle, data_bh);
+
+ ocfs2_xattr_update_xattr_search(inode, xs, xb_bh, xh_bh);
+
+ /* Change from ocfs2_xattr_header to ocfs2_xattr_tree_root */
+ memset(&xb->xb_attrs, 0, inode->i_sb->s_blocksize -
+ offsetof(struct ocfs2_xattr_block, xb_attrs));
+
+ xr = &xb->xb_attrs.xb_root;
+ xr->xt_clusters = cpu_to_le32(1);
+ xr->xt_last_eb_blk = 0;
+ xr->xt_list.l_tree_depth = 0;
+ xr->xt_list.l_count = cpu_to_le16(ocfs2_xattr_recs_per_xb(inode->i_sb));
+ xr->xt_list.l_next_free_rec = cpu_to_le16(1);
+
+ xr->xt_list.l_recs[0].e_cpos = 0;
+ xr->xt_list.l_recs[0].e_blkno = cpu_to_le64(blkno);
+ xr->xt_list.l_recs[0].e_leaf_clusters = cpu_to_le16(1);
+
+ xb->xb_flags = cpu_to_le16(xb_flags | OCFS2_XATTR_INDEXED);
+
+ ret = ocfs2_journal_dirty(handle, xb_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+
+out_sem:
+ up_write(&oi->ip_alloc_sem);
+
+out:
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+
+ brelse(xh_bh);
+ brelse(data_bh);
+
+ return ret;
+}
+
+static int cmp_xe_offset(const void *a, const void *b)
+{
+ const struct ocfs2_xattr_entry *l = a, *r = b;
+ u32 l_name_offset = le16_to_cpu(l->xe_name_offset);
+ u32 r_name_offset = le16_to_cpu(r->xe_name_offset);
+
+ if (l_name_offset < r_name_offset)
+ return 1;
+ if (l_name_offset > r_name_offset)
+ return -1;
+ return 0;
+}
+
+/*
+ * defrag a xattr bucket if we find that the bucket has some
+ * holes beteen name/value pairs.
+ * We will move all the name/value pairs to the end of the bucket
+ * so that we can spare some space for insertion.
+ */
+static int ocfs2_defrag_xattr_bucket(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket)
+{
+ int ret, i;
+ size_t end, offset, len, value_len;
+ struct ocfs2_xattr_header *xh;
+ char *entries, *buf, *bucket_buf = NULL;
+ u64 blkno = bucket->bhs[0]->b_blocknr;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ u16 xh_free_start;
+ size_t blocksize = inode->i_sb->s_blocksize;
+ handle_t *handle;
+ struct buffer_head **bhs;
+ struct ocfs2_xattr_entry *xe;
+
+ bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+ GFP_NOFS);
+ if (!bhs)
+ return -ENOMEM;
+
+ ret = ocfs2_read_blocks(inode, blkno, blk_per_bucket, bhs, 0);
+ if (ret)
+ goto out;
+
+ /*
+ * In order to make the operation more efficient and generic,
+ * we copy all the blocks into a contiguous memory and do the
+ * defragment there, so if anything is error, we will not touch
+ * the real block.
+ */
+ bucket_buf = kmalloc(OCFS2_XATTR_BUCKET_SIZE, GFP_NOFS);
+ if (!bucket_buf) {
+ ret = -EIO;
+ goto out;
+ }
+
+ buf = bucket_buf;
+ for (i = 0; i < blk_per_bucket; i++, buf += blocksize)
+ memcpy(buf, bhs[i]->b_data, blocksize);
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), blk_per_bucket);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ ret = ocfs2_journal_access(handle, inode, bhs[i],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto commit;
+ }
+ }
+
+ xh = (struct ocfs2_xattr_header *)bucket_buf;
+ entries = (char *)xh->xh_entries;
+ xh_free_start = le16_to_cpu(xh->xh_free_start);
+
+ mlog(0, "adjust xattr bucket in %llu, count = %u, "
+ "xh_free_start = %u, xh_name_value_len = %u.\n",
+ blkno, le16_to_cpu(xh->xh_count), xh_free_start,
+ le16_to_cpu(xh->xh_name_value_len));
+
+ /*
+ * sort all the entries by their offset.
+ * the largest will be the first, so that we can
+ * move them to the end one by one.
+ */
+ sort(entries, le16_to_cpu(xh->xh_count),
+ sizeof(struct ocfs2_xattr_entry),
+ cmp_xe_offset, swap_xe);
+
+ /* Move all name/values to the end of the bucket. */
+ xe = xh->xh_entries;
+ end = OCFS2_XATTR_BUCKET_SIZE;
+ for (i = 0; i < le16_to_cpu(xh->xh_count); i++, xe++) {
+ offset = le16_to_cpu(xe->xe_name_offset);
+ if (ocfs2_xattr_is_local(xe))
+ value_len = OCFS2_XATTR_SIZE(
+ le64_to_cpu(xe->xe_value_size));
+ else
+ value_len = OCFS2_XATTR_ROOT_SIZE;
+ len = OCFS2_XATTR_SIZE(xe->xe_name_len) + value_len;
+
+ /*
+ * We must make sure that the name/value pair
+ * exist in the same block. So adjust end to
+ * the previous block end if needed.
+ */
+ if (((end - len) / blocksize !=
+ (end - 1) / blocksize))
+ end = end - end % blocksize;
+
+ if (end > offset + len) {
+ memmove(bucket_buf + end - len,
+ bucket_buf + offset, len);
+ xe->xe_name_offset = cpu_to_le16(end - len);
+ }
+
+ mlog_bug_on_msg(end < offset + len, "Defrag check failed for "
+ "bucket %llu\n", (unsigned long long)blkno);
+
+ end -= len;
+ }
+
+ mlog_bug_on_msg(xh_free_start > end, "Defrag check failed for "
+ "bucket %llu\n", (unsigned long long)blkno);
+
+ if (xh_free_start == end)
+ goto commit;
+
+ memset(bucket_buf + xh_free_start, 0, end - xh_free_start);
+ xh->xh_free_start = cpu_to_le16(end);
+
+ /* sort the entries by their name_hash. */
+ sort(entries, le16_to_cpu(xh->xh_count),
+ sizeof(struct ocfs2_xattr_entry),
+ cmp_xe, swap_xe);
+
+ buf = bucket_buf;
+ for (i = 0; i < blk_per_bucket; i++, buf += blocksize) {
+ memcpy(bhs[i]->b_data, buf, blocksize);
+ ocfs2_journal_dirty(handle, bhs[i]);
+ }
+
+commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+out:
+
+ if (bhs) {
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(bhs[i]);
+ }
+ kfree(bhs);
+
+ kfree(bucket_buf);
+ return ret;
+}
+
+/*
+ * Move half nums of the xattr bucket in the previous cluster to this new
+ * cluster. We only touch the last cluster of the previous extend record.
+ *
+ * first_bh is the first buffer_head of a series of bucket in the same
+ * extent rec and header_bh is the header of one bucket in this cluster.
+ * They will be updated if we move the data header_bh contains to the new
+ * cluster. first_hash will be set as the 1st xe's name_hash of the new cluster.
+ */
+static int ocfs2_mv_xattr_bucket_cross_cluster(struct inode *inode,
+ handle_t *handle,
+ struct buffer_head **first_bh,
+ struct buffer_head **header_bh,
+ u64 new_blkno,
+ u64 prev_blkno,
+ u32 num_clusters,
+ u32 *first_hash)
+{
+ int i, ret, credits;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+ int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+ int blocksize = inode->i_sb->s_blocksize;
+ struct buffer_head *old_bh, *new_bh, *prev_bh, *new_first_bh = NULL;
+ struct ocfs2_xattr_header *new_xh;
+ struct ocfs2_xattr_header *xh =
+ (struct ocfs2_xattr_header *)((*first_bh)->b_data);
+
+ BUG_ON(le16_to_cpu(xh->xh_num_buckets) < num_buckets);
+ BUG_ON(OCFS2_XATTR_BUCKET_SIZE == osb->s_clustersize);
+
+ prev_bh = *first_bh;
+ get_bh(prev_bh);
+ xh = (struct ocfs2_xattr_header *)prev_bh->b_data;
+
+ prev_blkno += (num_clusters - 1) * bpc + bpc / 2;
+
+ mlog(0, "move half of xattrs in cluster %llu to %llu\n",
+ prev_blkno, new_blkno);
+
+ /*
+ * We need to update the 1st half of the new cluster and
+ * 1 more for the update of the 1st bucket of the previous
+ * extent record.
+ */
+ credits = bpc / 2 + 1;
+ ret = ocfs2_extend_trans(handle, credits);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, prev_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < bpc / 2; i++, prev_blkno++, new_blkno++) {
+ old_bh = new_bh = NULL;
+ new_bh = sb_getblk(inode->i_sb, new_blkno);
+ if (!new_bh) {
+ ret = -EIO;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ocfs2_set_new_buffer_uptodate(inode, new_bh);
+
+ ret = ocfs2_journal_access(handle, inode, new_bh,
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ brelse(new_bh);
+ goto out;
+ }
+
+ ret = ocfs2_read_block(inode, prev_blkno, &old_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ brelse(new_bh);
+ goto out;
+ }
+
+ memcpy(new_bh->b_data, old_bh->b_data, blocksize);
+
+ if (i == 0) {
+ new_xh = (struct ocfs2_xattr_header *)new_bh->b_data;
+ new_xh->xh_num_buckets = cpu_to_le16(num_buckets / 2);
+
+ if (first_hash)
+ *first_hash = le32_to_cpu(
+ new_xh->xh_entries[0].xe_name_hash);
+ new_first_bh = new_bh;
+ get_bh(new_first_bh);
+ }
+
+ ocfs2_journal_dirty(handle, new_bh);
+
+ if (*header_bh == old_bh) {
+ brelse(*header_bh);
+ *header_bh = new_bh;
+ get_bh(*header_bh);
+
+ brelse(*first_bh);
+ *first_bh = new_first_bh;
+ get_bh(*first_bh);
+ }
+ brelse(new_bh);
+ brelse(old_bh);
+ }
+
+ le16_add_cpu(&xh->xh_num_buckets, -(num_buckets / 2));
+
+ ocfs2_journal_dirty(handle, prev_bh);
+out:
+ brelse(prev_bh);
+ brelse(new_first_bh);
+ return ret;
+}
+
+static int ocfs2_read_xattr_bucket(struct inode *inode,
+ u64 blkno,
+ struct buffer_head **bhs,
+ int new)
+{
+ int ret = 0;
+ u16 i, blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+ if (!new)
+ return ocfs2_read_blocks(inode, blkno,
+ blk_per_bucket, bhs, 0);
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ bhs[i] = sb_getblk(inode->i_sb, blkno + i);
+ if (bhs[i] == NULL) {
+ ret = -EIO;
+ mlog_errno(ret);
+ break;
+ }
+ ocfs2_set_new_buffer_uptodate(inode, bhs[i]);
+ }
+
+ return ret;
+}
+
+/*
+ * Move half num of the xattrs in old bucket(blk) to new bucket(new_blk).
+ * first_hash will record the 1st hash of the new bucket.
+ */
+static int ocfs2_half_xattr_bucket(struct inode *inode,
+ handle_t *handle,
+ u64 blk,
+ u64 new_blk,
+ u32 *first_hash,
+ int new_bucket_head)
+{
+ int ret, i;
+ u16 count, start, len, name_value_len, xe_len, name_offset;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ struct buffer_head **s_bhs, **t_bhs = NULL;
+ struct ocfs2_xattr_header *xh;
+ struct ocfs2_xattr_entry *xe;
+ int blocksize = inode->i_sb->s_blocksize;
+
+ mlog(0, "move half of xattrs from bucket %llu to %llu\n",
+ blk, new_blk);
+
+ s_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+ if (!s_bhs)
+ return -ENOMEM;
+
+ ret = ocfs2_read_xattr_bucket(inode, blk, s_bhs, 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, s_bhs[0],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ t_bhs = kcalloc(blk_per_bucket, sizeof(struct buffer_head *), GFP_NOFS);
+ if (!t_bhs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = ocfs2_read_xattr_bucket(inode, new_blk, t_bhs, new_bucket_head);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+ OCFS2_JOURNAL_ACCESS_CREATE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ /* copy the whole bucket to the new first. */
+ for (i = 0; i < blk_per_bucket; i++)
+ memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+
+ /* update the new bucket. */
+ xh = (struct ocfs2_xattr_header *)t_bhs[0]->b_data;
+ count = le16_to_cpu(xh->xh_count);
+ start = count / 2;
+
+ /*
+ * Calculate the total name/value len and xh_free_start for
+ * the old bucket first.
+ */
+ name_offset = OCFS2_XATTR_BUCKET_SIZE;
+ name_value_len = 0;
+ for (i = 0; i < start; i++) {
+ xe = &xh->xh_entries[i];
+ xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+ if (ocfs2_xattr_is_local(xe))
+ xe_len +=
+ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+ else
+ xe_len += OCFS2_XATTR_ROOT_SIZE;
+ name_value_len += xe_len;
+ if (le16_to_cpu(xe->xe_name_offset) < name_offset)
+ name_offset = le16_to_cpu(xe->xe_name_offset);
+ }
+
+ /*
+ * Now begin the modification to the new bucket.
+ *
+ * In the new bucket, We just move the xattr entry to the beginning
+ * and don't touch the name/value. So there will be some holes in the
+ * bucket, and they will be removed when ocfs2_defrag_xattr_bucket is
+ * called.
+ */
+ xe = &xh->xh_entries[start];
+ len = sizeof(struct ocfs2_xattr_entry) * (count - start);
+ mlog(0, "mv xattr entry len %d from %d to %d\n", len,
+ (int)((char *)xe - (char *)xh),
+ (int)((char *)xh->xh_entries - (char *)xh));
+ memmove((char *)xh->xh_entries, (char *)xe, len);
+ xe = &xh->xh_entries[count - start];
+ len = sizeof(struct ocfs2_xattr_entry) * start;
+ memset((char *)xe, 0, len);
+
+ le16_add_cpu(&xh->xh_count, -start);
+ le16_add_cpu(&xh->xh_name_value_len, -name_value_len);
+
+ /* Calculate xh_free_start for the new bucket. */
+ xh->xh_free_start = cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+ xe = &xh->xh_entries[i];
+ xe_len = OCFS2_XATTR_SIZE(xe->xe_name_len);
+ if (ocfs2_xattr_is_local(xe))
+ xe_len +=
+ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+ else
+ xe_len += OCFS2_XATTR_ROOT_SIZE;
+ if (le16_to_cpu(xe->xe_name_offset) <
+ le16_to_cpu(xh->xh_free_start))
+ xh->xh_free_start = xe->xe_name_offset;
+ }
+
+ /* set xh->xh_num_buckets for the new xh. */
+ if (new_bucket_head)
+ xh->xh_num_buckets = cpu_to_le16(1);
+ else
+ xh->xh_num_buckets = 0;
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ ocfs2_journal_dirty(handle, t_bhs[i]);
+ if (ret)
+ mlog_errno(ret);
+ }
+
+ /* store the first_hash of the new bucket. */
+ if (first_hash)
+ *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+
+ /*
+ * Now only update the 1st block of the old bucket.
+ * Please note that the entry has been sorted already above.
+ */
+ xh = (struct ocfs2_xattr_header *)s_bhs[0]->b_data;
+ memset(&xh->xh_entries[start], 0,
+ sizeof(struct ocfs2_xattr_entry) * (count - start));
+ xh->xh_count = cpu_to_le16(start);
+ xh->xh_free_start = cpu_to_le16(name_offset);
+ xh->xh_name_value_len = cpu_to_le16(name_value_len);
+
+ ocfs2_journal_dirty(handle, s_bhs[0]);
+ if (ret)
+ mlog_errno(ret);
+
+out:
+ if (s_bhs) {
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(s_bhs[i]);
+ }
+ kfree(s_bhs);
+
+ if (t_bhs) {
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(t_bhs[i]);
+ }
+ kfree(t_bhs);
+
+ return ret;
+}
+
+/*
+ * Copy xattr from one bucket to another bucket.
+ *
+ * The caller must make sure that the journal transaction
+ * has enough space for journaling.
+ */
+static int ocfs2_cp_xattr_bucket(struct inode *inode,
+ handle_t *handle,
+ u64 s_blkno,
+ u64 t_blkno,
+ int t_is_new)
+{
+ int ret, i;
+ int blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ int blocksize = inode->i_sb->s_blocksize;
+ struct buffer_head **s_bhs, **t_bhs = NULL;
+
+ BUG_ON(s_blkno == t_blkno);
+
+ mlog(0, "cp bucket %llu to %llu, target is %d\n",
+ s_blkno, t_blkno, t_is_new);
+
+ s_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+ GFP_NOFS);
+ if (!s_bhs)
+ return -ENOMEM;
+
+ ret = ocfs2_read_xattr_bucket(inode, s_blkno, s_bhs, 0);
+ if (ret)
+ goto out;
+
+ t_bhs = kzalloc(sizeof(struct buffer_head *) * blk_per_bucket,
+ GFP_NOFS);
+ if (!t_bhs) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = ocfs2_read_xattr_bucket(inode, t_blkno, t_bhs, t_is_new);
+ if (ret)
+ goto out;
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ ret = ocfs2_journal_access(handle, inode, t_bhs[i],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret)
+ goto out;
+ }
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ memcpy(t_bhs[i]->b_data, s_bhs[i]->b_data, blocksize);
+ ocfs2_journal_dirty(handle, t_bhs[i]);
+ }
+
+out:
+ if (s_bhs) {
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(s_bhs[i]);
+ }
+ kfree(s_bhs);
+
+ if (t_bhs) {
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(t_bhs[i]);
+ }
+ kfree(t_bhs);
+
+ return ret;
+}
+
+/*
+ * Copy one xattr cluster from src_blk to to_blk.
+ * The to_blk will become the first bucket header of the cluster, so its
+ * xh_num_buckets will be initialized as the bucket num in the cluster.
+ */
+static int ocfs2_cp_xattr_cluster(struct inode *inode,
+ handle_t *handle,
+ struct buffer_head *first_bh,
+ u64 src_blk,
+ u64 to_blk,
+ u32 *first_hash)
+{
+ int i, ret, credits;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+ int num_buckets = ocfs2_xattr_buckets_per_cluster(osb);
+ struct buffer_head *bh = NULL;
+ struct ocfs2_xattr_header *xh;
+ u64 to_blk_start = to_blk;
+
+ mlog(0, "cp xattrs from cluster %llu to %llu\n", src_blk, to_blk);
+
+ /*
+ * We need to update the new cluster and 1 more for the update of
+ * the 1st bucket of the previous extent rec.
+ */
+ credits = bpc + 1;
+ ret = ocfs2_extend_trans(handle, credits);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, first_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < num_buckets; i++) {
+ ret = ocfs2_cp_xattr_bucket(inode, handle,
+ src_blk, to_blk, 1);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ src_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ to_blk += ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ }
+
+ /* update the old bucket header. */
+ xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+ le16_add_cpu(&xh->xh_num_buckets, -num_buckets);
+
+ ocfs2_journal_dirty(handle, first_bh);
+
+ /* update the new bucket header. */
+ ret = ocfs2_read_block(inode, to_blk_start, &bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xh = (struct ocfs2_xattr_header *)bh->b_data;
+ xh->xh_num_buckets = cpu_to_le16(num_buckets);
+
+ ocfs2_journal_dirty(handle, bh);
+
+ if (first_hash)
+ *first_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+out:
+ brelse(bh);
+ return ret;
+}
+
+/*
+ * Move half of the xattrs in this cluster to the new cluster.
+ * This function should only be called when bucket size == cluster size.
+ * Otherwise ocfs2_mv_xattr_bucket_cross_cluster should be used instead.
+ */
+static int ocfs2_half_xattr_cluster(struct inode *inode,
+ handle_t *handle,
+ u64 prev_blk,
+ u64 new_blk,
+ u32 *first_hash)
+{
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ int ret, credits = 2 * blk_per_bucket;
+
+ BUG_ON(OCFS2_XATTR_BUCKET_SIZE < OCFS2_SB(inode->i_sb)->s_clustersize);
+
+ ret = ocfs2_extend_trans(handle, credits);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ /* Move half of the xattr in start_blk to the next bucket. */
+ return ocfs2_half_xattr_bucket(inode, handle, prev_blk,
+ new_blk, first_hash, 1);
+}
+
+/*
+ * Move some xattrs from the old cluster to the new one since they are not
+ * contiguous in ocfs2 xattr tree.
+ *
+ * new_blk starts a new separate cluster, and we will move some xattrs from
+ * prev_blk to it. v_start will be set as the first name hash value in this
+ * new cluster so that it can be used as e_cpos during tree insertion and
+ * don't collide with our original b-tree operations. first_bh and header_bh
+ * will also be updated since they will be used in ocfs2_extend_xattr_bucket
+ * to extend the insert bucket.
+ *
+ * The problem is how much xattr should we move to the new one and when should
+ * we update first_bh and header_bh?
+ * 1. If cluster size > bucket size, that means the previous cluster has more
+ * than 1 bucket, so just move half nums of bucket into the new cluster and
+ * update the first_bh and header_bh if the insert bucket has been moved
+ * to the new cluster.
+ * 2. If cluster_size == bucket_size:
+ * a) If the previous extent rec has more than one cluster and the insert
+ * place isn't in the last cluster, copy the entire last cluster to the
+ * new one. This time, we don't need to upate the first_bh and header_bh
+ * since they will not be moved into the new cluster.
+ * b) Otherwise, move the bottom half of the xattrs in the last cluster into
+ * the new one. And we set the extend flag to zero if the insert place is
+ * moved into the new allocated cluster since no extend is needed.
+ */
+static int ocfs2_adjust_xattr_cross_cluster(struct inode *inode,
+ handle_t *handle,
+ struct buffer_head **first_bh,
+ struct buffer_head **header_bh,
+ u64 new_blk,
+ u64 prev_blk,
+ u32 prev_clusters,
+ u32 *v_start,
+ int *extend)
+{
+ int ret = 0;
+ int bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+
+ mlog(0, "adjust xattrs from cluster %llu len %u to %llu\n",
+ prev_blk, prev_clusters, new_blk);
+
+ if (ocfs2_xattr_buckets_per_cluster(OCFS2_SB(inode->i_sb)) > 1)
+ ret = ocfs2_mv_xattr_bucket_cross_cluster(inode,
+ handle,
+ first_bh,
+ header_bh,
+ new_blk,
+ prev_blk,
+ prev_clusters,
+ v_start);
+ else {
+ u64 last_blk = prev_blk + bpc * (prev_clusters - 1);
+
+ if (prev_clusters > 1 && (*header_bh)->b_blocknr != last_blk)
+ ret = ocfs2_cp_xattr_cluster(inode, handle, *first_bh,
+ last_blk, new_blk,
+ v_start);
+ else {
+ ret = ocfs2_half_xattr_cluster(inode, handle,
+ last_blk, new_blk,
+ v_start);
+
+ if ((*header_bh)->b_blocknr == last_blk && extend)
+ *extend = 0;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Add a new cluster for xattr storage.
+ *
+ * If the new cluster is contiguous with the previous one, it will be
+ * appended to the same extent record, and num_clusters will be updated.
+ * If not, we will insert a new extent for it and move some xattrs in
+ * the last cluster into the new allocated one.
+ * We also need to limit the maximum size of a btree leaf, otherwise we'll
+ * lose the benefits of hashing because we'll have to search large leaves.
+ * So now the maximum size is OCFS2_MAX_XATTR_TREE_LEAF_SIZE(or clustersize,
+ * if it's bigger).
+ *
+ * first_bh is the first block of the previous extent rec and header_bh
+ * indicates the bucket we will insert the new xattrs. They will be updated
+ * when the header_bh is moved into the new cluster.
+ */
+static int ocfs2_add_new_xattr_cluster(struct inode *inode,
+ struct buffer_head *root_bh,
+ struct buffer_head **first_bh,
+ struct buffer_head **header_bh,
+ u32 *num_clusters,
+ u32 prev_cpos,
+ u64 prev_blkno,
+ int *extend)
+{
+ int ret, credits;
+ u16 bpc = ocfs2_clusters_to_blocks(inode->i_sb, 1);
+ u32 prev_clusters = *num_clusters;
+ u32 clusters_to_add = 1, bit_off, num_bits, v_start = 0;
+ u64 block;
+ handle_t *handle = NULL;
+ struct ocfs2_alloc_context *data_ac = NULL;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct ocfs2_extent_tree et;
+
+ mlog(0, "Add new xattr cluster for %llu, previous xattr hash = %u, "
+ "previous xattr blkno = %llu\n",
+ (unsigned long long)OCFS2_I(inode)->ip_blkno,
+ prev_cpos, prev_blkno);
+
+ ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+ ret = ocfs2_lock_allocators(inode, &et, clusters_to_add, 0,
+ &data_ac, &meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ goto leave;
+ }
+
+ credits = ocfs2_calc_extend_credits(osb->sb, et.et_root_el,
+ clusters_to_add);
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(ret);
+ goto leave;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, root_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto leave;
+ }
+
+ ret = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+ clusters_to_add, &bit_off, &num_bits);
+ if (ret < 0) {
+ if (ret != -ENOSPC)
+ mlog_errno(ret);
+ goto leave;
+ }
+
+ BUG_ON(num_bits > clusters_to_add);
+
+ block = ocfs2_clusters_to_blocks(osb->sb, bit_off);
+ mlog(0, "Allocating %u clusters at block %u for xattr in inode %llu\n",
+ num_bits, bit_off, (unsigned long long)OCFS2_I(inode)->ip_blkno);
+
+ if (prev_blkno + prev_clusters * bpc == block &&
+ (prev_clusters + num_bits) << osb->s_clustersize_bits <=
+ OCFS2_MAX_XATTR_TREE_LEAF_SIZE) {
+ /*
+ * If this cluster is contiguous with the old one and
+ * adding this new cluster, we don't surpass the limit of
+ * OCFS2_MAX_XATTR_TREE_LEAF_SIZE, cool. We will let it be
+ * initialized and used like other buckets in the previous
+ * cluster.
+ * So add it as a contiguous one. The caller will handle
+ * its init process.
+ */
+ v_start = prev_cpos + prev_clusters;
+ *num_clusters = prev_clusters + num_bits;
+ mlog(0, "Add contiguous %u clusters to previous extent rec.\n",
+ num_bits);
+ } else {
+ ret = ocfs2_adjust_xattr_cross_cluster(inode,
+ handle,
+ first_bh,
+ header_bh,
+ block,
+ prev_blkno,
+ prev_clusters,
+ &v_start,
+ extend);
+ if (ret) {
+ mlog_errno(ret);
+ goto leave;
+ }
+ }
+
+ if (handle->h_buffer_credits < credits) {
+ /*
+ * The journal has been restarted before, and don't
+ * have enough space for the insertion, so extend it
+ * here.
+ */
+ ret = ocfs2_extend_trans(handle, credits);
+ if (ret) {
+ mlog_errno(ret);
+ goto leave;
+ }
+ }
+ mlog(0, "Insert %u clusters at block %llu for xattr at %u\n",
+ num_bits, block, v_start);
+ ret = ocfs2_insert_extent(osb, handle, inode, &et, v_start, block,
+ num_bits, 0, meta_ac);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto leave;
+ }
+
+ ret = ocfs2_journal_dirty(handle, root_bh);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto leave;
+ }
+
+leave:
+ if (handle)
+ ocfs2_commit_trans(osb, handle);
+ if (data_ac)
+ ocfs2_free_alloc_context(data_ac);
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+
+ return ret;
+}
+
+/*
+ * Extend a new xattr bucket and move xattrs to the end one by one until
+ * We meet with start_bh. Only move half of the xattrs to the bucket after it.
+ */
+static int ocfs2_extend_xattr_bucket(struct inode *inode,
+ struct buffer_head *first_bh,
+ struct buffer_head *start_bh,
+ u32 num_clusters)
+{
+ int ret, credits;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ u64 start_blk = start_bh->b_blocknr, end_blk;
+ u32 num_buckets = num_clusters * ocfs2_xattr_buckets_per_cluster(osb);
+ handle_t *handle;
+ struct ocfs2_xattr_header *first_xh =
+ (struct ocfs2_xattr_header *)first_bh->b_data;
+ u16 bucket = le16_to_cpu(first_xh->xh_num_buckets);
+
+ mlog(0, "extend xattr bucket in %llu, xattr extend rec starting "
+ "from %llu, len = %u\n", start_blk,
+ (unsigned long long)first_bh->b_blocknr, num_clusters);
+
+ BUG_ON(bucket >= num_buckets);
+
+ end_blk = first_bh->b_blocknr + (bucket - 1) * blk_per_bucket;
+
+ /*
+ * We will touch all the buckets after the start_bh(include it).
+ * Add one more bucket and modify the first_bh.
+ */
+ credits = end_blk - start_blk + 2 * blk_per_bucket + 1;
+ handle = ocfs2_start_trans(osb, credits);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, first_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto commit;
+ }
+
+ while (end_blk != start_blk) {
+ ret = ocfs2_cp_xattr_bucket(inode, handle, end_blk,
+ end_blk + blk_per_bucket, 0);
+ if (ret)
+ goto commit;
+ end_blk -= blk_per_bucket;
+ }
+
+ /* Move half of the xattr in start_blk to the next bucket. */
+ ret = ocfs2_half_xattr_bucket(inode, handle, start_blk,
+ start_blk + blk_per_bucket, NULL, 0);
+
+ le16_add_cpu(&first_xh->xh_num_buckets, 1);
+ ocfs2_journal_dirty(handle, first_bh);
+
+commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ return ret;
+}
+
+/*
+ * Add new xattr bucket in an extent record and adjust the buckets accordingly.
+ * xb_bh is the ocfs2_xattr_block.
+ * We will move all the buckets starting from header_bh to the next place. As
+ * for this one, half num of its xattrs will be moved to the next one.
+ *
+ * We will allocate a new cluster if current cluster is full and adjust
+ * header_bh and first_bh if the insert place is moved to the new cluster.
+ */
+static int ocfs2_add_new_xattr_bucket(struct inode *inode,
+ struct buffer_head *xb_bh,
+ struct buffer_head *header_bh)
+{
+ struct ocfs2_xattr_header *first_xh = NULL;
+ struct buffer_head *first_bh = NULL;
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)xb_bh->b_data;
+ struct ocfs2_xattr_tree_root *xb_root = &xb->xb_attrs.xb_root;
+ struct ocfs2_extent_list *el = &xb_root->xt_list;
+ struct ocfs2_xattr_header *xh =
+ (struct ocfs2_xattr_header *)header_bh->b_data;
+ u32 name_hash = le32_to_cpu(xh->xh_entries[0].xe_name_hash);
+ struct super_block *sb = inode->i_sb;
+ struct ocfs2_super *osb = OCFS2_SB(sb);
+ int ret, num_buckets, extend = 1;
+ u64 p_blkno;
+ u32 e_cpos, num_clusters;
+
+ mlog(0, "Add new xattr bucket starting form %llu\n",
+ (unsigned long long)header_bh->b_blocknr);
+
+ /*
+ * Add refrence for header_bh here because it may be
+ * changed in ocfs2_add_new_xattr_cluster and we need
+ * to free it in the end.
+ */
+ get_bh(header_bh);
+
+ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno, &e_cpos,
+ &num_clusters, el);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_read_block(inode, p_blkno, &first_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ num_buckets = ocfs2_xattr_buckets_per_cluster(osb) * num_clusters;
+ first_xh = (struct ocfs2_xattr_header *)first_bh->b_data;
+
+ if (num_buckets == le16_to_cpu(first_xh->xh_num_buckets)) {
+ ret = ocfs2_add_new_xattr_cluster(inode,
+ xb_bh,
+ &first_bh,
+ &header_bh,
+ &num_clusters,
+ e_cpos,
+ p_blkno,
+ &extend);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ if (extend)
+ ret = ocfs2_extend_xattr_bucket(inode,
+ first_bh,
+ header_bh,
+ num_clusters);
+ if (ret)
+ mlog_errno(ret);
+out:
+ brelse(first_bh);
+ brelse(header_bh);
+ return ret;
+}
+
+static inline char *ocfs2_xattr_bucket_get_val(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket,
+ int offs)
+{
+ int block_off = offs >> inode->i_sb->s_blocksize_bits;
+
+ offs = offs % inode->i_sb->s_blocksize;
+ return bucket->bhs[block_off]->b_data + offs;
+}
+
+/*
+ * Handle the normal xattr set, including replace, delete and new.
+ *
+ * Note: "local" indicates the real data's locality. So we can't
+ * just its bucket locality by its length.
+ */
+static void ocfs2_xattr_set_entry_normal(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ u32 name_hash,
+ int local)
+{
+ struct ocfs2_xattr_entry *last, *xe;
+ int name_len = strlen(xi->name);
+ struct ocfs2_xattr_header *xh = xs->header;
+ u16 count = le16_to_cpu(xh->xh_count), start;
+ size_t blocksize = inode->i_sb->s_blocksize;
+ char *val;
+ size_t offs, size, new_size;
+
+ last = &xh->xh_entries[count];
+ if (!xs->not_found) {
+ xe = xs->here;
+ offs = le16_to_cpu(xe->xe_name_offset);
+ if (ocfs2_xattr_is_local(xe))
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+ else
+ size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+ /*
+ * If the new value will be stored outside, xi->value has been
+ * initalized as an empty ocfs2_xattr_value_root, and the same
+ * goes with xi->value_len, so we can set new_size safely here.
+ * See ocfs2_xattr_set_in_bucket.
+ */
+ new_size = OCFS2_XATTR_SIZE(name_len) +
+ OCFS2_XATTR_SIZE(xi->value_len);
+
+ le16_add_cpu(&xh->xh_name_value_len, -size);
+ if (xi->value) {
+ if (new_size > size)
+ goto set_new_name_value;
+
+ /* Now replace the old value with new one. */
+ if (local)
+ xe->xe_value_size = cpu_to_le64(xi->value_len);
+ else
+ xe->xe_value_size = 0;
+
+ val = ocfs2_xattr_bucket_get_val(inode,
+ &xs->bucket, offs);
+ memset(val + OCFS2_XATTR_SIZE(name_len), 0,
+ size - OCFS2_XATTR_SIZE(name_len));
+ if (OCFS2_XATTR_SIZE(xi->value_len) > 0)
+ memcpy(val + OCFS2_XATTR_SIZE(name_len),
+ xi->value, xi->value_len);
+
+ le16_add_cpu(&xh->xh_name_value_len, new_size);
+ ocfs2_xattr_set_local(xe, local);
+ return;
+ } else {
+ /*
+ * Remove the old entry if there is more than one.
+ * We don't remove the last entry so that we can
+ * use it to indicate the hash value of the empty
+ * bucket.
+ */
+ last -= 1;
+ le16_add_cpu(&xh->xh_count, -1);
+ if (xh->xh_count) {
+ memmove(xe, xe + 1,
+ (void *)last - (void *)xe);
+ memset(last, 0,
+ sizeof(struct ocfs2_xattr_entry));
+ } else
+ xh->xh_free_start =
+ cpu_to_le16(OCFS2_XATTR_BUCKET_SIZE);
+
+ return;
+ }
+ } else {
+ /* find a new entry for insert. */
+ int low = 0, high = count - 1, tmp;
+ struct ocfs2_xattr_entry *tmp_xe;
+
+ while (low <= high && count) {
+ tmp = (low + high) / 2;
+ tmp_xe = &xh->xh_entries[tmp];
+
+ if (name_hash > le32_to_cpu(tmp_xe->xe_name_hash))
+ low = tmp + 1;
+ else if (name_hash <
+ le32_to_cpu(tmp_xe->xe_name_hash))
+ high = tmp - 1;
+ else {
+ low = tmp;
+ break;
+ }
+ }
+
+ xe = &xh->xh_entries[low];
+ if (low != count)
+ memmove(xe + 1, xe, (void *)last - (void *)xe);
+
+ le16_add_cpu(&xh->xh_count, 1);
+ memset(xe, 0, sizeof(struct ocfs2_xattr_entry));
+ xe->xe_name_hash = cpu_to_le32(name_hash);
+ xe->xe_name_len = name_len;
+ ocfs2_xattr_set_type(xe, xi->name_index);
+ }
+
+set_new_name_value:
+ /* Insert the new name+value. */
+ size = OCFS2_XATTR_SIZE(name_len) + OCFS2_XATTR_SIZE(xi->value_len);
+
+ /*
+ * We must make sure that the name/value pair
+ * exists in the same block.
+ */
+ offs = le16_to_cpu(xh->xh_free_start);
+ start = offs - size;
+
+ if (start >> inode->i_sb->s_blocksize_bits !=
+ (offs - 1) >> inode->i_sb->s_blocksize_bits) {
+ offs = offs - offs % blocksize;
+ xh->xh_free_start = cpu_to_le16(offs);
+ }
+
+ val = ocfs2_xattr_bucket_get_val(inode,
+ &xs->bucket, offs - size);
+ xe->xe_name_offset = cpu_to_le16(offs - size);
+
+ memset(val, 0, size);
+ memcpy(val, xi->name, name_len);
+ memcpy(val + OCFS2_XATTR_SIZE(name_len), xi->value, xi->value_len);
+
+ xe->xe_value_size = cpu_to_le64(xi->value_len);
+ ocfs2_xattr_set_local(xe, local);
+ xs->here = xe;
+ le16_add_cpu(&xh->xh_free_start, -size);
+ le16_add_cpu(&xh->xh_name_value_len, size);
+
+ return;
+}
+
+static int ocfs2_xattr_bucket_handle_journal(struct inode *inode,
+ handle_t *handle,
+ struct ocfs2_xattr_search *xs,
+ struct buffer_head **bhs,
+ u16 bh_num)
+{
+ int ret = 0, off, block_off;
+ struct ocfs2_xattr_entry *xe = xs->here;
+
+ /*
+ * First calculate all the blocks we should journal_access
+ * and journal_dirty. The first block should always be touched.
+ */
+ ret = ocfs2_journal_dirty(handle, bhs[0]);
+ if (ret)
+ mlog_errno(ret);
+
+ /* calc the data. */
+ off = le16_to_cpu(xe->xe_name_offset);
+ block_off = off >> inode->i_sb->s_blocksize_bits;
+ ret = ocfs2_journal_dirty(handle, bhs[block_off]);
+ if (ret)
+ mlog_errno(ret);
+
+ return ret;
+}
+
+/*
+ * Set the xattr entry in the specified bucket.
+ * The bucket is indicated by xs->bucket and it should have the enough
+ * space for the xattr insertion.
+ */
+static int ocfs2_xattr_set_entry_in_bucket(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs,
+ u32 name_hash,
+ int local)
+{
+ int i, ret;
+ handle_t *handle = NULL;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ mlog(0, "Set xattr entry len = %lu index = %d in bucket %llu\n",
+ (unsigned long)xi->value_len, xi->name_index,
+ (unsigned long long)xs->bucket.bhs[0]->b_blocknr);
+
+ if (!xs->bucket.bhs[1]) {
+ ret = ocfs2_read_blocks(inode,
+ xs->bucket.bhs[0]->b_blocknr + 1,
+ blk_per_bucket - 1, &xs->bucket.bhs[1],
+ 0);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans(osb, blk_per_bucket);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ handle = NULL;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < blk_per_bucket; i++) {
+ ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[i],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ ocfs2_xattr_set_entry_normal(inode, xi, xs, name_hash, local);
+
+ /*Only dirty the blocks we have touched in set xattr. */
+ ret = ocfs2_xattr_bucket_handle_journal(inode, handle, xs,
+ xs->bucket.bhs, blk_per_bucket);
+ if (ret)
+ mlog_errno(ret);
+out:
+ ocfs2_commit_trans(osb, handle);
+
+ return ret;
+}
+
+static int ocfs2_xattr_value_update_size(struct inode *inode,
+ struct buffer_head *xe_bh,
+ struct ocfs2_xattr_entry *xe,
+ u64 new_size)
+{
+ int ret;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ handle_t *handle = NULL;
+
+ handle = ocfs2_start_trans(osb, 1);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, xe_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ xe->xe_value_size = cpu_to_le64(new_size);
+
+ ret = ocfs2_journal_dirty(handle, xe_bh);
+ if (ret < 0)
+ mlog_errno(ret);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ return ret;
+}
+
+/*
+ * Truncate the specified xe_off entry in xattr bucket.
+ * bucket is indicated by header_bh and len is the new length.
+ * Both the ocfs2_xattr_value_root and the entry will be updated here.
+ *
+ * Copy the new updated xe and xe_value_root to new_xe and new_xv if needed.
+ */
+static int ocfs2_xattr_bucket_value_truncate(struct inode *inode,
+ struct buffer_head *header_bh,
+ int xe_off,
+ int len)
+{
+ int ret, offset;
+ u64 value_blk;
+ struct buffer_head *value_bh = NULL;
+ struct ocfs2_xattr_value_root *xv;
+ struct ocfs2_xattr_entry *xe;
+ struct ocfs2_xattr_header *xh =
+ (struct ocfs2_xattr_header *)header_bh->b_data;
+ size_t blocksize = inode->i_sb->s_blocksize;
+
+ xe = &xh->xh_entries[xe_off];
+
+ BUG_ON(!xe || ocfs2_xattr_is_local(xe));
+
+ offset = le16_to_cpu(xe->xe_name_offset) +
+ OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+ value_blk = offset / blocksize;
+
+ /* We don't allow ocfs2_xattr_value to be stored in different block. */
+ BUG_ON(value_blk != (offset + OCFS2_XATTR_ROOT_SIZE - 1) / blocksize);
+ value_blk += header_bh->b_blocknr;
+
+ ret = ocfs2_read_block(inode, value_blk, &value_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xv = (struct ocfs2_xattr_value_root *)
+ (value_bh->b_data + offset % blocksize);
+
+ mlog(0, "truncate %u in xattr bucket %llu to %d bytes.\n",
+ xe_off, (unsigned long long)header_bh->b_blocknr, len);
+ ret = ocfs2_xattr_value_truncate(inode, value_bh, xv, len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_xattr_value_update_size(inode, header_bh, xe, len);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+out:
+ brelse(value_bh);
+ return ret;
+}
+
+static int ocfs2_xattr_bucket_value_truncate_xs(struct inode *inode,
+ struct ocfs2_xattr_search *xs,
+ int len)
+{
+ int ret, offset;
+ struct ocfs2_xattr_entry *xe = xs->here;
+ struct ocfs2_xattr_header *xh = (struct ocfs2_xattr_header *)xs->base;
+
+ BUG_ON(!xs->bucket.bhs[0] || !xe || ocfs2_xattr_is_local(xe));
+
+ offset = xe - xh->xh_entries;
+ ret = ocfs2_xattr_bucket_value_truncate(inode, xs->bucket.bhs[0],
+ offset, len);
+ if (ret)
+ mlog_errno(ret);
+
+ return ret;
+}
+
+static int ocfs2_xattr_bucket_set_value_outside(struct inode *inode,
+ struct ocfs2_xattr_search *xs,
+ char *val,
+ int value_len)
+{
+ int offset;
+ struct ocfs2_xattr_value_root *xv;
+ struct ocfs2_xattr_entry *xe = xs->here;
+
+ BUG_ON(!xs->base || !xe || ocfs2_xattr_is_local(xe));
+
+ offset = le16_to_cpu(xe->xe_name_offset) +
+ OCFS2_XATTR_SIZE(xe->xe_name_len);
+
+ xv = (struct ocfs2_xattr_value_root *)(xs->base + offset);
+
+ return __ocfs2_xattr_set_value_outside(inode, xv, val, value_len);
+}
+
+static int ocfs2_rm_xattr_cluster(struct inode *inode,
+ struct buffer_head *root_bh,
+ u64 blkno,
+ u32 cpos,
+ u32 len)
+{
+ int ret;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+ struct inode *tl_inode = osb->osb_tl_inode;
+ handle_t *handle;
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)root_bh->b_data;
+ struct ocfs2_alloc_context *meta_ac = NULL;
+ struct ocfs2_cached_dealloc_ctxt dealloc;
+ struct ocfs2_extent_tree et;
+
+ ocfs2_init_xattr_tree_extent_tree(&et, inode, root_bh);
+
+ ocfs2_init_dealloc_ctxt(&dealloc);
+
+ mlog(0, "rm xattr extent rec at %u len = %u, start from %llu\n",
+ cpos, len, (unsigned long long)blkno);
+
+ ocfs2_remove_xattr_clusters_from_cache(inode, blkno, len);
+
+ ret = ocfs2_lock_allocators(inode, &et, 0, 1, NULL, &meta_ac);
+ if (ret) {
+ mlog_errno(ret);
+ return ret;
+ }
+
+ mutex_lock(&tl_inode->i_mutex);
+
+ if (ocfs2_truncate_log_needs_flush(osb)) {
+ ret = __ocfs2_flush_truncate_log(osb);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ }
+
+ handle = ocfs2_start_trans(osb, OCFS2_REMOVE_EXTENT_CREDITS);
+ if (handle == NULL) {
+ ret = -ENOMEM;
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, root_bh,
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_remove_extent(inode, &et, cpos, len, handle, meta_ac,
+ &dealloc);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ le32_add_cpu(&xb->xb_attrs.xb_root.xt_clusters, -len);
+
+ ret = ocfs2_journal_dirty(handle, root_bh);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ ret = ocfs2_truncate_log_append(osb, handle, blkno, len);
+ if (ret)
+ mlog_errno(ret);
+
+out_commit:
+ ocfs2_commit_trans(osb, handle);
+out:
+ ocfs2_schedule_truncate_log_flush(osb, 1);
+
+ mutex_unlock(&tl_inode->i_mutex);
+
+ if (meta_ac)
+ ocfs2_free_alloc_context(meta_ac);
+
+ ocfs2_run_deallocs(osb, &dealloc);
+
+ return ret;
+}
+
+static void ocfs2_xattr_bucket_remove_xs(struct inode *inode,
+ struct ocfs2_xattr_search *xs)
+{
+ handle_t *handle = NULL;
+ struct ocfs2_xattr_header *xh = xs->bucket.xh;
+ struct ocfs2_xattr_entry *last = &xh->xh_entries[
+ le16_to_cpu(xh->xh_count) - 1];
+ int ret = 0;
+
+ handle = ocfs2_start_trans((OCFS2_SB(inode->i_sb)), 1);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ mlog_errno(ret);
+ return;
+ }
+
+ ret = ocfs2_journal_access(handle, inode, xs->bucket.bhs[0],
+ OCFS2_JOURNAL_ACCESS_WRITE);
+ if (ret) {
+ mlog_errno(ret);
+ goto out_commit;
+ }
+
+ /* Remove the old entry. */
+ memmove(xs->here, xs->here + 1,
+ (void *)last - (void *)xs->here);
+ memset(last, 0, sizeof(struct ocfs2_xattr_entry));
+ le16_add_cpu(&xh->xh_count, -1);
+
+ ret = ocfs2_journal_dirty(handle, xs->bucket.bhs[0]);
+ if (ret < 0)
+ mlog_errno(ret);
+out_commit:
+ ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle);
+}
+
+/*
+ * Set the xattr name/value in the bucket specified in xs.
+ *
+ * As the new value in xi may be stored in the bucket or in an outside cluster,
+ * we divide the whole process into 3 steps:
+ * 1. insert name/value in the bucket(ocfs2_xattr_set_entry_in_bucket)
+ * 2. truncate of the outside cluster(ocfs2_xattr_bucket_value_truncate_xs)
+ * 3. Set the value to the outside cluster(ocfs2_xattr_bucket_set_value_outside)
+ * 4. If the clusters for the new outside value can't be allocated, we need
+ * to free the xattr we allocated in set.
+ */
+static int ocfs2_xattr_set_in_bucket(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs)
+{
+ int ret, local = 1;
+ size_t value_len;
+ char *val = (char *)xi->value;
+ struct ocfs2_xattr_entry *xe = xs->here;
+ u32 name_hash = ocfs2_xattr_name_hash(inode, xi->name,
+ strlen(xi->name));
+
+ if (!xs->not_found && !ocfs2_xattr_is_local(xe)) {
+ /*
+ * We need to truncate the xattr storage first.
+ *
+ * If both the old and new value are stored to
+ * outside block, we only need to truncate
+ * the storage and then set the value outside.
+ *
+ * If the new value should be stored within block,
+ * we should free all the outside block first and
+ * the modification to the xattr block will be done
+ * by following steps.
+ */
+ if (xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+ value_len = xi->value_len;
+ else
+ value_len = 0;
+
+ ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+ value_len);
+ if (ret)
+ goto out;
+
+ if (value_len)
+ goto set_value_outside;
+ }
+
+ value_len = xi->value_len;
+ /* So we have to handle the inside block change now. */
+ if (value_len > OCFS2_XATTR_INLINE_SIZE) {
+ /*
+ * If the new value will be stored outside of block,
+ * initalize a new empty value root and insert it first.
+ */
+ local = 0;
+ xi->value = &def_xv;
+ xi->value_len = OCFS2_XATTR_ROOT_SIZE;
+ }
+
+ ret = ocfs2_xattr_set_entry_in_bucket(inode, xi, xs, name_hash, local);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ if (value_len <= OCFS2_XATTR_INLINE_SIZE)
+ goto out;
+
+ /* allocate the space now for the outside block storage. */
+ ret = ocfs2_xattr_bucket_value_truncate_xs(inode, xs,
+ value_len);
+ if (ret) {
+ mlog_errno(ret);
+
+ if (xs->not_found) {
+ /*
+ * We can't allocate enough clusters for outside
+ * storage and we have allocated xattr already,
+ * so need to remove it.
+ */
+ ocfs2_xattr_bucket_remove_xs(inode, xs);
+ }
+ goto out;
+ }
+
+set_value_outside:
+ ret = ocfs2_xattr_bucket_set_value_outside(inode, xs, val, value_len);
+out:
+ return ret;
+}
+
+/* check whether the xattr bucket is filled up with the same hash value. */
+static int ocfs2_check_xattr_bucket_collision(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket)
+{
+ struct ocfs2_xattr_header *xh = bucket->xh;
+
+ if (xh->xh_entries[le16_to_cpu(xh->xh_count) - 1].xe_name_hash ==
+ xh->xh_entries[0].xe_name_hash) {
+ mlog(ML_ERROR, "Too much hash collision in xattr bucket %llu, "
+ "hash = %u\n",
+ (unsigned long long)bucket->bhs[0]->b_blocknr,
+ le32_to_cpu(xh->xh_entries[0].xe_name_hash));
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int ocfs2_xattr_set_entry_index_block(struct inode *inode,
+ struct ocfs2_xattr_info *xi,
+ struct ocfs2_xattr_search *xs)
+{
+ struct ocfs2_xattr_header *xh;
+ struct ocfs2_xattr_entry *xe;
+ u16 count, header_size, xh_free_start;
+ int i, free, max_free, need, old;
+ size_t value_size = 0, name_len = strlen(xi->name);
+ size_t blocksize = inode->i_sb->s_blocksize;
+ int ret, allocation = 0;
+ u16 blk_per_bucket = ocfs2_blocks_per_xattr_bucket(inode->i_sb);
+
+ mlog_entry("Set xattr %s in xattr index block\n", xi->name);
+
+try_again:
+ xh = xs->header;
+ count = le16_to_cpu(xh->xh_count);
+ xh_free_start = le16_to_cpu(xh->xh_free_start);
+ header_size = sizeof(struct ocfs2_xattr_header) +
+ count * sizeof(struct ocfs2_xattr_entry);
+ max_free = OCFS2_XATTR_BUCKET_SIZE -
+ le16_to_cpu(xh->xh_name_value_len) - header_size;
+
+ mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size "
+ "of %u which exceed block size\n",
+ (unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+ header_size);
+
+ if (xi->value && xi->value_len > OCFS2_XATTR_INLINE_SIZE)
+ value_size = OCFS2_XATTR_ROOT_SIZE;
+ else if (xi->value)
+ value_size = OCFS2_XATTR_SIZE(xi->value_len);
+
+ if (xs->not_found)
+ need = sizeof(struct ocfs2_xattr_entry) +
+ OCFS2_XATTR_SIZE(name_len) + value_size;
+ else {
+ need = value_size + OCFS2_XATTR_SIZE(name_len);
+
+ /*
+ * We only replace the old value if the new length is smaller
+ * than the old one. Otherwise we will allocate new space in the
+ * bucket to store it.
+ */
+ xe = xs->here;
+ if (ocfs2_xattr_is_local(xe))
+ old = OCFS2_XATTR_SIZE(le64_to_cpu(xe->xe_value_size));
+ else
+ old = OCFS2_XATTR_SIZE(OCFS2_XATTR_ROOT_SIZE);
+
+ if (old >= value_size)
+ need = 0;
+ }
+
+ free = xh_free_start - header_size;
+ /*
+ * We need to make sure the new name/value pair
+ * can exist in the same block.
+ */
+ if (xh_free_start % blocksize < need)
+ free -= xh_free_start % blocksize;
+
+ mlog(0, "xs->not_found = %d, in xattr bucket %llu: free = %d, "
+ "need = %d, max_free = %d, xh_free_start = %u, xh_name_value_len ="
+ " %u\n", xs->not_found,
+ (unsigned long long)xs->bucket.bhs[0]->b_blocknr,
+ free, need, max_free, le16_to_cpu(xh->xh_free_start),
+ le16_to_cpu(xh->xh_name_value_len));
+
+ if (free < need || count == ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+ if (need <= max_free &&
+ count < ocfs2_xattr_max_xe_in_bucket(inode->i_sb)) {
+ /*
+ * We can create the space by defragment. Since only the
+ * name/value will be moved, the xe shouldn't be changed
+ * in xs.
+ */
+ ret = ocfs2_defrag_xattr_bucket(inode, &xs->bucket);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ xh_free_start = le16_to_cpu(xh->xh_free_start);
+ free = xh_free_start - header_size;
+ if (xh_free_start % blocksize < need)
+ free -= xh_free_start % blocksize;
+
+ if (free >= need)
+ goto xattr_set;
+
+ mlog(0, "Can't get enough space for xattr insert by "
+ "defragment. Need %u bytes, but we have %d, so "
+ "allocate new bucket for it.\n", need, free);
+ }
+
+ /*
+ * We have to add new buckets or clusters and one
+ * allocation should leave us enough space for insert.
+ */
+ BUG_ON(allocation);
+
+ /*
+ * We do not allow for overlapping ranges between buckets. And
+ * the maximum number of collisions we will allow for then is
+ * one bucket's worth, so check it here whether we need to
+ * add a new bucket for the insert.
+ */
+ ret = ocfs2_check_xattr_bucket_collision(inode, &xs->bucket);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_add_new_xattr_bucket(inode,
+ xs->xattr_bh,
+ xs->bucket.bhs[0]);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ for (i = 0; i < blk_per_bucket; i++)
+ brelse(xs->bucket.bhs[i]);
+
+ memset(&xs->bucket, 0, sizeof(xs->bucket));
+
+ ret = ocfs2_xattr_index_block_find(inode, xs->xattr_bh,
+ xi->name_index,
+ xi->name, xs);
+ if (ret && ret != -ENODATA)
+ goto out;
+ xs->not_found = ret;
+ allocation = 1;
+ goto try_again;
+ }
+
+xattr_set:
+ ret = ocfs2_xattr_set_in_bucket(inode, xi, xs);
+out:
+ mlog_exit(ret);
+ return ret;
+}
+
+static int ocfs2_delete_xattr_in_bucket(struct inode *inode,
+ struct ocfs2_xattr_bucket *bucket,
+ void *para)
+{
+ int ret = 0;
+ struct ocfs2_xattr_header *xh = bucket->xh;
+ u16 i;
+ struct ocfs2_xattr_entry *xe;
+
+ for (i = 0; i < le16_to_cpu(xh->xh_count); i++) {
+ xe = &xh->xh_entries[i];
+ if (ocfs2_xattr_is_local(xe))
+ continue;
+
+ ret = ocfs2_xattr_bucket_value_truncate(inode,
+ bucket->bhs[0],
+ i, 0);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int ocfs2_delete_xattr_index_block(struct inode *inode,
+ struct buffer_head *xb_bh)
+{
+ struct ocfs2_xattr_block *xb =
+ (struct ocfs2_xattr_block *)xb_bh->b_data;
+ struct ocfs2_extent_list *el = &xb->xb_attrs.xb_root.xt_list;
+ int ret = 0;
+ u32 name_hash = UINT_MAX, e_cpos, num_clusters;
+ u64 p_blkno;
+
+ if (le16_to_cpu(el->l_next_free_rec) == 0)
+ return 0;
+
+ while (name_hash > 0) {
+ ret = ocfs2_xattr_get_rec(inode, name_hash, &p_blkno,
+ &e_cpos, &num_clusters, el);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_iterate_xattr_buckets(inode, p_blkno, num_clusters,
+ ocfs2_delete_xattr_in_bucket,
+ NULL);
+ if (ret) {
+ mlog_errno(ret);
+ goto out;
+ }
+
+ ret = ocfs2_rm_xattr_cluster(inode, xb_bh,
+ p_blkno, e_cpos, num_clusters);
+ if (ret) {
+ mlog_errno(ret);
+ break;
+ }
+
+ if (e_cpos == 0)
+ break;
+
+ name_hash = e_cpos - 1;
+ }
+
+out:
+ return ret;
+}
+
+/*
+ * 'trusted' attributes support
+ */
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+static size_t ocfs2_xattr_trusted_list(struct inode *inode, char *list,
+ size_t list_size, const char *name,
+ size_t name_len)
+{
+ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX) - 1;
+ const size_t total_len = prefix_len + name_len + 1;
+
+ if (list && total_len <= list_size) {
+ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+ memcpy(list + prefix_len, name, name_len);
+ list[prefix_len + name_len] = '\0';
+ }
+ return total_len;
+}
+
+static int ocfs2_xattr_trusted_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_TRUSTED, name,
+ buffer, size);
+}
+
+static int ocfs2_xattr_trusted_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+
+ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_TRUSTED, name, value,
+ size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_trusted_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .list = ocfs2_xattr_trusted_list,
+ .get = ocfs2_xattr_trusted_get,
+ .set = ocfs2_xattr_trusted_set,
+};
+
+
+/*
+ * 'user' attributes support
+ */
+
+#define XATTR_USER_PREFIX "user."
+
+static size_t ocfs2_xattr_user_list(struct inode *inode, char *list,
+ size_t list_size, const char *name,
+ size_t name_len)
+{
+ const size_t prefix_len = sizeof(XATTR_USER_PREFIX) - 1;
+ const size_t total_len = prefix_len + name_len + 1;
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+ return 0;
+
+ if (list && total_len <= list_size) {
+ memcpy(list, XATTR_USER_PREFIX, prefix_len);
+ memcpy(list + prefix_len, name, name_len);
+ list[prefix_len + name_len] = '\0';
+ }
+ return total_len;
+}
+
+static int ocfs2_xattr_user_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+ return -EOPNOTSUPP;
+ return ocfs2_xattr_get(inode, OCFS2_XATTR_INDEX_USER, name,
+ buffer, size);
+}
+
+static int ocfs2_xattr_user_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+ return -EOPNOTSUPP;
+
+ return ocfs2_xattr_set(inode, OCFS2_XATTR_INDEX_USER, name, value,
+ size, flags);
+}
+
+struct xattr_handler ocfs2_xattr_user_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .list = ocfs2_xattr_user_list,
+ .get = ocfs2_xattr_user_get,
+ .set = ocfs2_xattr_user_set,
+};
diff --git a/fs/ocfs2/xattr.h b/fs/ocfs2/xattr.h
new file mode 100644
index 00000000000..c25c7c62a05
--- /dev/null
+++ b/fs/ocfs2/xattr.h
@@ -0,0 +1,68 @@
+/* -*- mode: c; c-basic-offset: 8; -*-
+ * vim: noexpandtab sw=8 ts=8 sts=0:
+ *
+ * xattr.h
+ *
+ * Function prototypes
+ *
+ * Copyright (C) 2008 Oracle. All rights reserved.
+ *
+ * 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 021110-1307, USA.
+ */
+
+#ifndef OCFS2_XATTR_H
+#define OCFS2_XATTR_H
+
+#include <linux/init.h>
+#include <linux/xattr.h>
+
+enum ocfs2_xattr_type {
+ OCFS2_XATTR_INDEX_USER = 1,
+ OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS,
+ OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT,
+ OCFS2_XATTR_INDEX_TRUSTED,
+ OCFS2_XATTR_INDEX_SECURITY,
+ OCFS2_XATTR_MAX
+};
+
+extern struct xattr_handler ocfs2_xattr_user_handler;
+extern struct xattr_handler ocfs2_xattr_trusted_handler;
+
+extern ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
+extern int ocfs2_xattr_get(struct inode *, int, const char *, void *, size_t);
+extern int ocfs2_xattr_set(struct inode *, int, const char *, const void *,
+ size_t, int);
+extern int ocfs2_xattr_remove(struct inode *inode, struct buffer_head *di_bh);
+extern struct xattr_handler *ocfs2_xattr_handlers[];
+
+static inline u16 ocfs2_xattr_buckets_per_cluster(struct ocfs2_super *osb)
+{
+ return (1 << osb->s_clustersize_bits) / OCFS2_XATTR_BUCKET_SIZE;
+}
+
+static inline u16 ocfs2_blocks_per_xattr_bucket(struct super_block *sb)
+{
+ return OCFS2_XATTR_BUCKET_SIZE / (1 << sb->s_blocksize_bits);
+}
+
+static inline u16 ocfs2_xattr_max_xe_in_bucket(struct super_block *sb)
+{
+ u16 len = sb->s_blocksize -
+ offsetof(struct ocfs2_xattr_header, xh_entries);
+
+ return len / sizeof(struct ocfs2_xattr_entry);
+}
+#endif /* OCFS2_XATTR_H */
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c
index 3d3e1663147..a97b477ac0f 100644
--- a/fs/partitions/acorn.c
+++ b/fs/partitions/acorn.c
@@ -275,16 +275,6 @@ adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev)
id = data[0x1fc] & 15;
put_dev_sector(sect);
-#ifdef CONFIG_BLK_DEV_MFM
- if (MAJOR(bdev->bd_dev) == MFM_ACORN_MAJOR) {
- extern void xd_set_geometry(struct block_device *,
- unsigned char, unsigned char, unsigned int);
- xd_set_geometry(bdev, dr->secspertrack, heads, 1);
- invalidate_bh_lrus();
- truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
- }
-#endif
-
/*
* Work out start of non-adfs partition.
*/
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 7408227c49c..fbeb2f372a9 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -538,10 +538,23 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev)
sector_t from = state->parts[p].from;
if (!size)
continue;
+ if (from >= get_capacity(disk)) {
+ printk(KERN_WARNING
+ "%s: p%d ignored, start %llu is behind the end of the disk\n",
+ disk->disk_name, p, (unsigned long long) from);
+ continue;
+ }
if (from + size > get_capacity(disk)) {
+ /*
+ * we can not ignore partitions of broken tables
+ * created by for example camera firmware, but we
+ * limit them to the end of the disk to avoid
+ * creating invalid block devices
+ */
printk(KERN_WARNING
- "%s: p%d exceeds device capacity\n",
- disk->disk_name, p);
+ "%s: p%d size %llu limited to end of disk\n",
+ disk->disk_name, p, (unsigned long long) size);
+ size = get_capacity(disk) - from;
}
res = add_partition(disk, p, from, size, state->parts[p].flags);
if (res) {
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 66c1ab87656..59ea42e1ef0 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -45,7 +45,6 @@
#include <linux/blkdev.h>
#include <linux/hugetlb.h>
#include <linux/jiffies.h>
-#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
#include <linux/pid_namespace.h>
@@ -683,6 +682,7 @@ static int cmdline_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}
+#ifdef CONFIG_FILE_LOCKING
static int locks_open(struct inode *inode, struct file *filp)
{
return seq_open(filp, &locks_seq_operations);
@@ -694,6 +694,7 @@ static const struct file_operations proc_locks_operations = {
.llseek = seq_lseek,
.release = seq_release,
};
+#endif /* CONFIG_FILE_LOCKING */
static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
@@ -702,28 +703,6 @@ static int execdomains_read_proc(char *page, char **start, off_t off,
return proc_calc_metrics(page, start, off, count, eof, len);
}
-#ifdef CONFIG_MAGIC_SYSRQ
-/*
- * writing 'C' to /proc/sysrq-trigger is like sysrq-C
- */
-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- if (count) {
- char c;
-
- if (get_user(c, buf))
- return -EFAULT;
- __handle_sysrq(c, NULL, 0);
- }
- return count;
-}
-
-static const struct file_operations proc_sysrq_trigger_operations = {
- .write = write_sysrq_trigger,
-};
-#endif
-
#ifdef CONFIG_PROC_PAGE_MONITOR
#define KPMSIZE sizeof(u64)
#define KPMMASK (KPMSIZE - 1)
@@ -887,7 +866,9 @@ void __init proc_misc_init(void)
#ifdef CONFIG_PRINTK
proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
#endif
+#ifdef CONFIG_FILE_LOCKING
proc_create("locks", 0, NULL, &proc_locks_operations);
+#endif
proc_create("devices", 0, NULL, &proc_devinfo_operations);
proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK
@@ -930,7 +911,4 @@ void __init proc_misc_init(void)
#ifdef CONFIG_PROC_VMCORE
proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
#endif
-#ifdef CONFIG_MAGIC_SYSRQ
- proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
-#endif
}
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index b9dbeeca704..37173fa07d1 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -8,8 +8,6 @@
/* proc info support a la one created by Sizif@Botik.RU for PGC */
-/* $Id: procfs.c,v 1.1.8.2 2001/07/15 17:08:42 god Exp $ */
-
#include <linux/module.h>
#include <linux/time.h>
#include <linux/seq_file.h>
@@ -621,7 +619,6 @@ int reiserfs_global_version_in_proc(char *buffer, char **start,
#endif
/*
- * $Log: procfs.c,v $
* Revision 1.1.8.2 2001/07/15 17:08:42 god
* . use get_super() in procfs.c
* . remove remove_save_link() from reiserfs_do_truncate()
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index bb3cb5b7cdb..ad92461cbfc 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -155,7 +155,7 @@ static struct dentry *get_xa_file_dentry(const struct inode *inode,
xadir = open_xa_dir(inode, flags);
if (IS_ERR(xadir)) {
return ERR_CAST(xadir);
- } else if (xadir && !xadir->d_inode) {
+ } else if (!xadir->d_inode) {
dput(xadir);
return ERR_PTR(-ENODATA);
}
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 7227b2efef2..e39013619b2 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1323,7 +1323,7 @@ xfs_fs_remount(
"XFS: mount option \"%s\" not supported for remount\n", p);
return -EINVAL;
#else
- return 0;
+ break;
#endif
}
}
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 57ab9e9d759..74a9617776a 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -467,7 +467,7 @@ struct acpi_integer_overlay {
/*
* If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header,
* define it now. This is the case where there the compiler does not support
- * a __FUNCTION__ macro or equivalent.
+ * a __func__ macro or equivalent.
*/
#ifndef ACPI_GET_FUNCTION_NAME
#define ACPI_GET_FUNCTION_NAME _acpi_function_name
@@ -475,12 +475,12 @@ struct acpi_integer_overlay {
* The Name parameter should be the procedure name as a quoted string.
* The function name is 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__.
+ * and macros such as __func__.
*/
#define ACPI_FUNCTION_NAME(name) static const char _acpi_function_name[] = #name;
#else
-/* Compiler supports __FUNCTION__ (or equivalent) -- Ignore this macro */
+/* Compiler supports __func__ (or equivalent) -- Ignore this macro */
#define ACPI_FUNCTION_NAME(name)
#endif
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 8996dba90cd..8e2cdc57b19 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -46,7 +46,7 @@
/* Function name is used for debug output. Non-ANSI, compiler-dependent */
-#define ACPI_GET_FUNCTION_NAME __FUNCTION__
+#define ACPI_GET_FUNCTION_NAME __func__
/*
* This macro is used to tag functions as "printf-like" because
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index edc6ba82e09..0f6dabd4b51 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -22,7 +22,7 @@ struct bug_entry {
#ifndef HAVE_ARCH_BUG
#define BUG() do { \
- printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
+ printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \
panic("BUG!"); \
} while (0)
#endif
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 0f99ad38b01..81797ec9ab2 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -35,11 +35,17 @@ struct module;
* @label: for diagnostics
* @dev: optional device providing the GPIOs
* @owner: helps prevent removal of modules exporting active GPIOs
+ * @request: optional hook for chip-specific activation, such as
+ * enabling module power and clock; may sleep
+ * @free: optional hook for chip-specific deactivation, such as
+ * disabling module power and clock; may sleep
* @direction_input: configures signal "offset" as input, or returns error
* @get: returns value for signal "offset"; for output signals this
* returns either the value actually sensed, or zero
* @direction_output: configures signal "offset" as output, or returns error
* @set: assigns output value for signal "offset"
+ * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
+ * implementation may not sleep
* @dbg_show: optional routine to show contents in debugfs; default code
* will be used when this is omitted, but custom code can show extra
* state (such as pullup/pulldown configuration).
@@ -61,10 +67,15 @@ struct module;
* is calculated by subtracting @base from the gpio number.
*/
struct gpio_chip {
- char *label;
+ const char *label;
struct device *dev;
struct module *owner;
+ int (*request)(struct gpio_chip *chip,
+ unsigned offset);
+ void (*free)(struct gpio_chip *chip,
+ unsigned offset);
+
int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
@@ -73,6 +84,10 @@ struct gpio_chip {
unsigned offset, int value);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);
+
+ int (*to_irq)(struct gpio_chip *chip,
+ unsigned offset);
+
void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int base;
@@ -112,6 +127,7 @@ extern void __gpio_set_value(unsigned gpio, int value);
extern int __gpio_cansleep(unsigned gpio);
+extern int __gpio_to_irq(unsigned gpio);
#ifdef CONFIG_GPIO_SYSFS
diff --git a/include/asm-h8300/timer.h b/include/asm-h8300/timer.h
new file mode 100644
index 00000000000..def80464d38
--- /dev/null
+++ b/include/asm-h8300/timer.h
@@ -0,0 +1,25 @@
+#ifndef __H8300_TIMER_H
+#define __H8300_TIMER_H
+
+void h8300_timer_tick(void);
+void h8300_timer_setup(void);
+void h8300_gettod(unsigned int *year, unsigned int *mon, unsigned int *day,
+ unsigned int *hour, unsigned int *min, unsigned int *sec);
+
+#define TIMER_FREQ (CONFIG_CPU_CLOCK*10000) /* Timer input freq. */
+
+#define calc_param(cnt, div, rate, limit) \
+do { \
+ cnt = TIMER_FREQ / HZ; \
+ for (div = 0; div < ARRAY_SIZE(divide_rate); div++) { \
+ if (rate[div] == 0) \
+ continue; \
+ if ((cnt / rate[div]) > limit) \
+ break; \
+ } \
+ if (div == ARRAY_SIZE(divide_rate)) \
+ panic("Timer counter overflow"); \
+ cnt /= divide_rate[div]; \
+} while(0)
+
+#endif
diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h
index ecf007df774..1412b4ab202 100644
--- a/include/asm-m68k/atarihw.h
+++ b/include/asm-m68k/atarihw.h
@@ -39,7 +39,6 @@ extern int atari_dont_touch_floppy_select;
#define MACH_IS_TT ((atari_mch_cookie >> 16) == ATARI_MCH_TT)
#define MACH_IS_FALCON ((atari_mch_cookie >> 16) == ATARI_MCH_FALCON)
#define MACH_IS_MEDUSA (atari_mch_type == ATARI_MACH_MEDUSA)
-#define MACH_IS_HADES (atari_mch_type == ATARI_MACH_HADES)
#define MACH_IS_AB40 (atari_mch_type == ATARI_MACH_AB40)
/* values for atari_switches */
diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
index 91f7944333d..26f505488c1 100644
--- a/include/asm-m68k/dma-mapping.h
+++ b/include/asm-m68k/dma-mapping.h
@@ -74,6 +74,14 @@ extern void dma_sync_single_for_device(struct device *, dma_addr_t, size_t,
extern void dma_sync_sg_for_device(struct device *, struct scatterlist *, int,
enum dma_data_direction);
+static inline void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ /* just sync everything for now */
+ dma_sync_single_for_device(dev, dma_handle, offset + size, direction);
+}
+
static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
size_t size, enum dma_data_direction dir)
{
@@ -84,6 +92,14 @@ static inline void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *s
{
}
+static inline void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ /* just sync everything for now */
+ dma_sync_single_for_cpu(dev, dma_handle, offset + size, direction);
+}
+
static inline int dma_mapping_error(struct device *dev, dma_addr_t handle)
{
return 0;
diff --git a/include/asm-m68k/dma.h b/include/asm-m68k/dma.h
index d0c9e61e57b..4240fbc946f 100644
--- a/include/asm-m68k/dma.h
+++ b/include/asm-m68k/dma.h
@@ -11,10 +11,6 @@
extern int request_dma(unsigned int dmanr, const char * device_id); /* reserve a DMA channel */
extern void free_dma(unsigned int dmanr); /* release it again */
-#ifdef CONFIG_PCI
-extern int isa_dma_bridge_buggy;
-#else
#define isa_dma_bridge_buggy (0)
-#endif
#endif /* _M68K_DMA_H */
diff --git a/include/asm-m68k/entry.h b/include/asm-m68k/entry.h
index f8f6b185d79..5202f5a5b42 100644
--- a/include/asm-m68k/entry.h
+++ b/include/asm-m68k/entry.h
@@ -31,7 +31,7 @@
*/
/* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY) && !defined(CONFIG_HADES)
+#if defined(MACH_ATARI_ONLY)
/* block out HSYNC on the atari */
#define ALLOWINT (~0x400)
#define MAX_NOINT_IPL 3
diff --git a/include/asm-m68k/io.h b/include/asm-m68k/io.h
index 657187f0c7c..9e673e3bd43 100644
--- a/include/asm-m68k/io.h
+++ b/include/asm-m68k/io.h
@@ -7,15 +7,12 @@
* - added skeleton for GG-II and Amiga PCMCIA
* 2/3/01 RZ: - moved a few more defs into raw_io.h
*
- * inX/outX/readX/writeX should not be used by any driver unless it does
- * ISA or PCI access. Other drivers should use function defined in raw_io.h
+ * inX/outX should not be used by any driver unless it does
+ * ISA access. Other drivers should use function defined in raw_io.h
* or define its own macros on top of these.
*
- * inX(),outX() are for PCI and ISA I/O
- * readX(),writeX() are for PCI memory
+ * inX(),outX() are for ISA I/O
* isa_readX(),isa_writeX() are for ISA memory
- *
- * moved mem{cpy,set}_*io inside CONFIG_PCI
*/
#ifndef _IO_H
@@ -256,10 +253,7 @@ static inline void isa_delay(void)
(ISA_SEX ? raw_outsl(isa_itl(port), (u32 *)(buf), (nr)) : \
raw_outsw_swapw(isa_itw(port), (u16 *)(buf), (nr)<<1))
-#endif /* CONFIG_ISA */
-
-#if defined(CONFIG_ISA) && !defined(CONFIG_PCI)
#define inb isa_inb
#define inb_p isa_inb_p
#define outb isa_outb
@@ -282,55 +276,9 @@ static inline void isa_delay(void)
#define readw isa_readw
#define writeb isa_writeb
#define writew isa_writew
-#endif /* CONFIG_ISA */
-
-#if defined(CONFIG_PCI)
-
-#define readl(addr) in_le32(addr)
-#define writel(val,addr) out_le32((addr),(val))
-
-/* those can be defined for both ISA and PCI - it won't work though */
-#define readb(addr) in_8(addr)
-#define readw(addr) in_le16(addr)
-#define writeb(val,addr) out_8((addr),(val))
-#define writew(val,addr) out_le16((addr),(val))
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
+#else /* CONFIG_ISA */
-#ifndef CONFIG_ISA
-#define inb(port) in_8(port)
-#define outb(val,port) out_8((port),(val))
-#define inw(port) in_le16(port)
-#define outw(val,port) out_le16((port),(val))
-#define inl(port) in_le32(port)
-#define outl(val,port) out_le32((port),(val))
-
-#else
-/*
- * kernel with both ISA and PCI compiled in, those have
- * conflicting defs for in/out. Simply consider port < 1024
- * ISA and everything else PCI. read,write not defined
- * in this case
- */
-#define inb(port) ((port)<1024 ? isa_inb(port) : in_8(port))
-#define inb_p(port) ((port)<1024 ? isa_inb_p(port) : in_8(port))
-#define inw(port) ((port)<1024 ? isa_inw(port) : in_le16(port))
-#define inw_p(port) ((port)<1024 ? isa_inw_p(port) : in_le16(port))
-#define inl(port) ((port)<1024 ? isa_inl(port) : in_le32(port))
-#define inl_p(port) ((port)<1024 ? isa_inl_p(port) : in_le32(port))
-
-#define outb(val,port) ((port)<1024 ? isa_outb((val),(port)) : out_8((port),(val)))
-#define outb_p(val,port) ((port)<1024 ? isa_outb_p((val),(port)) : out_8((port),(val)))
-#define outw(val,port) ((port)<1024 ? isa_outw((val),(port)) : out_le16((port),(val)))
-#define outw_p(val,port) ((port)<1024 ? isa_outw_p((val),(port)) : out_le16((port),(val)))
-#define outl(val,port) ((port)<1024 ? isa_outl((val),(port)) : out_le32((port),(val)))
-#define outl_p(val,port) ((port)<1024 ? isa_outl_p((val),(port)) : out_le32((port),(val)))
-#endif
-#endif /* CONFIG_PCI */
-
-#if !defined(CONFIG_ISA) && !defined(CONFIG_PCI)
/*
* We need to define dummy functions for GENERIC_IOMAP support.
*/
@@ -357,11 +305,11 @@ static inline void isa_delay(void)
#define writeb(val,addr) out_8((addr),(val))
#define readw(addr) in_le16(addr)
#define writew(val,addr) out_le16((addr),(val))
-#endif
-#if !defined(CONFIG_PCI)
+
+#endif /* CONFIG_ISA */
+
#define readl(addr) in_le32(addr)
#define writel(val,addr) out_le32((addr),(val))
-#endif
#define mmiowb()
diff --git a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h
index 678cb0b5231..4ad0aea48ab 100644
--- a/include/asm-m68k/pci.h
+++ b/include/asm-m68k/pci.h
@@ -1,52 +1,7 @@
#ifndef _ASM_M68K_PCI_H
#define _ASM_M68K_PCI_H
-/*
- * asm-m68k/pci_m68k.h - m68k specific PCI declarations.
- *
- * Written by Wout Klaren.
- */
-
-#include <asm/scatterlist.h>
-
-struct pci_ops;
-
-/*
- * Structure with hardware dependent information and functions of the
- * PCI bus.
- */
-
-struct pci_bus_info
-{
- /*
- * Resources of the PCI bus.
- */
-
- struct resource mem_space;
- struct resource io_space;
-
- /*
- * System dependent functions.
- */
-
- struct pci_ops *m68k_pci_ops;
-
- void (*fixup)(int pci_modify);
- void (*conf_device)(struct pci_dev *dev);
-};
-
-#define pcibios_assign_all_busses() 0
-#define pcibios_scan_all_fns(a, b) 0
-
-static inline void pcibios_set_master(struct pci_dev *dev)
-{
- /* No special bus mastering setup handling */
-}
-
-static inline void pcibios_penalize_isa_irq(int irq, int active)
-{
- /* We don't do dynamic PCI IRQ allocation */
-}
+#include <asm-generic/pci-dma-compat.h>
/* The PCI address space does equal the physical memory
* address space. The networking and block device layers use
diff --git a/include/asm-m68k/virtconvert.h b/include/asm-m68k/virtconvert.h
index dea32fbc7e5..22ab05c9c52 100644
--- a/include/asm-m68k/virtconvert.h
+++ b/include/asm-m68k/virtconvert.h
@@ -40,15 +40,9 @@ static inline void *phys_to_virt(unsigned long address)
/*
* IO bus memory addresses are 1:1 with the physical address,
- * except on the PCI bus of the Hades.
*/
-#ifdef CONFIG_HADES
-#define virt_to_bus(a) (virt_to_phys(a) + (MACH_IS_HADES ? 0x80000000 : 0))
-#define bus_to_virt(a) (phys_to_virt((a) - (MACH_IS_HADES ? 0x80000000 : 0)))
-#else
#define virt_to_bus virt_to_phys
#define bus_to_virt phys_to_virt
-#endif
#endif
#endif
diff --git a/include/asm-x86/es7000/apic.h b/include/asm-x86/es7000/apic.h
index bd2c44d1f7a..aae50c2fb30 100644
--- a/include/asm-x86/es7000/apic.h
+++ b/include/asm-x86/es7000/apic.h
@@ -171,7 +171,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
int new_apicid = cpu_to_logical_apicid(cpu);
if (apicid_cluster(apicid) !=
apicid_cluster(new_apicid)){
- printk ("%s: Not a valid mask!\n",__FUNCTION__);
+ printk ("%s: Not a valid mask!\n", __func__);
#if defined CONFIG_ES7000_CLUSTERED_APIC
return 0xFF;
#else
diff --git a/include/asm-x86/iommu.h b/include/asm-x86/iommu.h
index 546ad3110fe..961e746da97 100644
--- a/include/asm-x86/iommu.h
+++ b/include/asm-x86/iommu.h
@@ -8,7 +8,7 @@ extern int force_iommu, no_iommu;
extern int iommu_detected;
extern int dmar_disabled;
-extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len);
+extern unsigned long iommu_nr_pages(unsigned long addr, unsigned long len);
#ifdef CONFIG_GART_IOMMU
extern int gart_iommu_aperture;
diff --git a/include/asm-x86/summit/apic.h b/include/asm-x86/summit/apic.h
index c5b2e4b1035..394b00bb5e7 100644
--- a/include/asm-x86/summit/apic.h
+++ b/include/asm-x86/summit/apic.h
@@ -160,7 +160,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
int new_apicid = cpu_to_logical_apicid(cpu);
if (apicid_cluster(apicid) !=
apicid_cluster(new_apicid)){
- printk ("%s: Not a valid mask!\n",__FUNCTION__);
+ printk ("%s: Not a valid mask!\n", __func__);
return 0xFF;
}
apicid = apicid | new_apicid;
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 09b276c3522..f6b8cf99b59 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -204,12 +204,21 @@ struct kioctx {
/* prototypes */
extern unsigned aio_max_size;
+#ifdef CONFIG_AIO
extern ssize_t wait_on_sync_kiocb(struct kiocb *iocb);
extern int aio_put_req(struct kiocb *iocb);
extern void kick_iocb(struct kiocb *iocb);
extern int aio_complete(struct kiocb *iocb, long res, long res2);
struct mm_struct;
extern void exit_aio(struct mm_struct *mm);
+#else
+static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; }
+static inline int aio_put_req(struct kiocb *iocb) { return 0; }
+static inline void kick_iocb(struct kiocb *iocb) { }
+static inline int aio_complete(struct kiocb *iocb, long res, long res2) { return 0; }
+struct mm_struct;
+static inline void exit_aio(struct mm_struct *mm) { }
+#endif /* CONFIG_AIO */
#define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait)
diff --git a/include/linux/auto_dev-ioctl.h b/include/linux/auto_dev-ioctl.h
new file mode 100644
index 00000000000..f4d05ccd731
--- /dev/null
+++ b/include/linux/auto_dev-ioctl.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2008 Red Hat, Inc. All rights reserved.
+ * Copyright 2008 Ian Kent <raven@themaw.net>
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ */
+
+#ifndef _LINUX_AUTO_DEV_IOCTL_H
+#define _LINUX_AUTO_DEV_IOCTL_H
+
+#include <linux/types.h>
+
+#define AUTOFS_DEVICE_NAME "autofs"
+
+#define AUTOFS_DEV_IOCTL_VERSION_MAJOR 1
+#define AUTOFS_DEV_IOCTL_VERSION_MINOR 0
+
+#define AUTOFS_DEVID_LEN 16
+
+#define AUTOFS_DEV_IOCTL_SIZE sizeof(struct autofs_dev_ioctl)
+
+/*
+ * An ioctl interface for autofs mount point control.
+ */
+
+/*
+ * All the ioctls use this structure.
+ * When sending a path size must account for the total length
+ * of the chunk of memory otherwise is is the size of the
+ * structure.
+ */
+
+struct autofs_dev_ioctl {
+ __u32 ver_major;
+ __u32 ver_minor;
+ __u32 size; /* total size of data passed in
+ * including this struct */
+ __s32 ioctlfd; /* automount command fd */
+
+ __u32 arg1; /* Command parameters */
+ __u32 arg2;
+
+ char path[0];
+};
+
+static inline void init_autofs_dev_ioctl(struct autofs_dev_ioctl *in)
+{
+ in->ver_major = AUTOFS_DEV_IOCTL_VERSION_MAJOR;
+ in->ver_minor = AUTOFS_DEV_IOCTL_VERSION_MINOR;
+ in->size = sizeof(struct autofs_dev_ioctl);
+ in->ioctlfd = -1;
+ in->arg1 = 0;
+ in->arg2 = 0;
+ return;
+}
+
+/*
+ * If you change this make sure you make the corresponding change
+ * to autofs-dev-ioctl.c:lookup_ioctl()
+ */
+enum {
+ /* Get various version info */
+ AUTOFS_DEV_IOCTL_VERSION_CMD = 0x71,
+ AUTOFS_DEV_IOCTL_PROTOVER_CMD,
+ AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD,
+
+ /* Open mount ioctl fd */
+ AUTOFS_DEV_IOCTL_OPENMOUNT_CMD,
+
+ /* Close mount ioctl fd */
+ AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD,
+
+ /* Mount/expire status returns */
+ AUTOFS_DEV_IOCTL_READY_CMD,
+ AUTOFS_DEV_IOCTL_FAIL_CMD,
+
+ /* Activate/deactivate autofs mount */
+ AUTOFS_DEV_IOCTL_SETPIPEFD_CMD,
+ AUTOFS_DEV_IOCTL_CATATONIC_CMD,
+
+ /* Expiry timeout */
+ AUTOFS_DEV_IOCTL_TIMEOUT_CMD,
+
+ /* Get mount last requesting uid and gid */
+ AUTOFS_DEV_IOCTL_REQUESTER_CMD,
+
+ /* Check for eligible expire candidates */
+ AUTOFS_DEV_IOCTL_EXPIRE_CMD,
+
+ /* Request busy status */
+ AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD,
+
+ /* Check if path is a mountpoint */
+ AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD,
+};
+
+#define AUTOFS_IOCTL 0x93
+
+#define AUTOFS_DEV_IOCTL_VERSION \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_VERSION_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOVER \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_PROTOVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_PROTOSUBVER \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_PROTOSUBVER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_OPENMOUNT \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_OPENMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CLOSEMOUNT \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_CLOSEMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_READY \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_READY_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_FAIL \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_FAIL_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_SETPIPEFD \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_SETPIPEFD_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_CATATONIC \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_CATATONIC_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_TIMEOUT \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_TIMEOUT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_REQUESTER \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_REQUESTER_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_EXPIRE \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_EXPIRE_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ASKUMOUNT \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_ASKUMOUNT_CMD, struct autofs_dev_ioctl)
+
+#define AUTOFS_DEV_IOCTL_ISMOUNTPOINT \
+ _IOWR(AUTOFS_IOCTL, \
+ AUTOFS_DEV_IOCTL_ISMOUNTPOINT_CMD, struct autofs_dev_ioctl)
+
+#endif /* _LINUX_AUTO_DEV_IOCTL_H */
diff --git a/include/linux/auto_fs4.h b/include/linux/auto_fs4.h
index b785c6f8644..2253716d4b9 100644
--- a/include/linux/auto_fs4.h
+++ b/include/linux/auto_fs4.h
@@ -23,12 +23,17 @@
#define AUTOFS_MIN_PROTO_VERSION 3
#define AUTOFS_MAX_PROTO_VERSION 5
-#define AUTOFS_PROTO_SUBVERSION 0
+#define AUTOFS_PROTO_SUBVERSION 1
/* Mask for expire behaviour */
#define AUTOFS_EXP_IMMEDIATE 1
#define AUTOFS_EXP_LEAVES 2
+#define AUTOFS_TYPE_ANY 0x0000
+#define AUTOFS_TYPE_INDIRECT 0x0001
+#define AUTOFS_TYPE_DIRECT 0x0002
+#define AUTOFS_TYPE_OFFSET 0x0004
+
/* Daemon notification packet types */
enum autofs_notify {
NFY_NONE,
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index 826f6235080..7394b5b349f 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -36,6 +36,10 @@ struct linux_binprm{
unsigned long p; /* current top of mem */
unsigned int sh_bang:1,
misc_bang:1;
+#ifdef __alpha__
+ unsigned int taso:1;
+#endif
+ unsigned int recursion_depth;
struct file * file;
int e_uid, e_gid;
kernel_cap_t cap_post_exec_permitted;
@@ -58,6 +62,7 @@ struct linux_binprm{
#define BINPRM_FLAGS_EXECFD_BIT 1
#define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT)
+#define BINPRM_MAX_RECURSION 4
/*
* This structure defines the functions that are used to load the binary formats that
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index c98dd7cb707..30934e4bfaa 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -326,7 +326,8 @@ struct cgroup_subsys {
*/
void (*mm_owner_changed)(struct cgroup_subsys *ss,
struct cgroup *old,
- struct cgroup *new);
+ struct cgroup *new,
+ struct task_struct *p);
int subsys_id;
int active;
int disabled;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 5ca8c6fddb5..778777316ea 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -35,6 +35,8 @@ struct clk;
* clk_get may return different clock producers depending on @dev.)
*
* Drivers must assume that the clock source is not enabled.
+ *
+ * clk_get should not be called from within interrupt context.
*/
struct clk *clk_get(struct device *dev, const char *id);
@@ -76,6 +78,8 @@ unsigned long clk_get_rate(struct clk *clk);
* Note: drivers must ensure that all clk_enable calls made on this
* clock source are balanced by clk_disable calls prior to calling
* this function.
+ *
+ * clk_put should not be called from within interrupt context.
*/
void clk_put(struct clk *clk);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index cf8d11cad5a..f061a1ea1b7 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -78,7 +78,6 @@ typedef struct {
compat_sigset_word sig[_COMPAT_NSIG_WORDS];
} compat_sigset_t;
-extern int cp_compat_stat(struct kstat *, struct compat_stat __user *);
extern int get_compat_timespec(struct timespec *, const struct compat_timespec __user *);
extern int put_compat_timespec(const struct timespec *, struct compat_timespec __user *);
@@ -235,6 +234,11 @@ extern int get_compat_itimerspec(struct itimerspec *dst,
extern int put_compat_itimerspec(struct compat_itimerspec __user *dst,
const struct itimerspec *src);
+asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
+ struct timezone __user *tz);
+asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+ struct timezone __user *tz);
+
asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
extern int compat_printk(const char *fmt, ...);
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index b03f80a078b..d71f7c0f931 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -53,7 +53,6 @@ struct vc_data {
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
struct console_font vc_font; /* Current VC font set */
unsigned short vc_video_erase_char; /* Background erase character */
- unsigned short vc_scrl_erase_char; /* Erase character for scroll */
/* VT terminal data */
unsigned int vc_state; /* Escape sequence parser state */
unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
diff --git a/include/linux/ds1286.h b/include/linux/ds1286.h
index d8989860e4c..45ea0aa0aeb 100644
--- a/include/linux/ds1286.h
+++ b/include/linux/ds1286.h
@@ -8,8 +8,6 @@
#ifndef __LINUX_DS1286_H
#define __LINUX_DS1286_H
-#include <asm/ds1286.h>
-
/**********************************************************************
* register summary
**********************************************************************/
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 2efe7b863cf..78c775a83f7 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -47,7 +47,7 @@
#ifdef EXT2FS_DEBUG
# define ext2_debug(f, a...) { \
printk ("EXT2-fs DEBUG (%s, %d): %s:", \
- __FILE__, __LINE__, __FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
printk (f, ## a); \
}
#else
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 8120fa1bc23..159d9b476cd 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -43,7 +43,7 @@
#define ext3_debug(f, a...) \
do { \
printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \
- __FILE__, __LINE__, __FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
printk (KERN_DEBUG f, ## a); \
} while (0)
#else
@@ -871,7 +871,7 @@ extern void ext3_update_dynamic_rev (struct super_block *sb);
#define ext3_std_error(sb, errno) \
do { \
if ((errno)) \
- __ext3_std_error((sb), __FUNCTION__, (errno)); \
+ __ext3_std_error((sb), __func__, (errno)); \
} while (0)
/*
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
index 8c43b13a02f..cf82d519be4 100644
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -137,17 +137,17 @@ int __ext3_journal_dirty_metadata(const char *where,
handle_t *handle, struct buffer_head *bh);
#define ext3_journal_get_undo_access(handle, bh) \
- __ext3_journal_get_undo_access(__FUNCTION__, (handle), (bh))
+ __ext3_journal_get_undo_access(__func__, (handle), (bh))
#define ext3_journal_get_write_access(handle, bh) \
- __ext3_journal_get_write_access(__FUNCTION__, (handle), (bh))
+ __ext3_journal_get_write_access(__func__, (handle), (bh))
#define ext3_journal_revoke(handle, blocknr, bh) \
- __ext3_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
+ __ext3_journal_revoke(__func__, (handle), (blocknr), (bh))
#define ext3_journal_get_create_access(handle, bh) \
- __ext3_journal_get_create_access(__FUNCTION__, (handle), (bh))
+ __ext3_journal_get_create_access(__func__, (handle), (bh))
#define ext3_journal_dirty_metadata(handle, bh) \
- __ext3_journal_dirty_metadata(__FUNCTION__, (handle), (bh))
+ __ext3_journal_dirty_metadata(__func__, (handle), (bh))
#define ext3_journal_forget(handle, bh) \
- __ext3_journal_forget(__FUNCTION__, (handle), (bh))
+ __ext3_journal_forget(__func__, (handle), (bh))
int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
@@ -160,7 +160,7 @@ static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks)
}
#define ext3_journal_stop(handle) \
- __ext3_journal_stop(__FUNCTION__, (handle))
+ __ext3_journal_stop(__func__, (handle))
static inline handle_t *ext3_journal_current_handle(void)
{
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 44e3cb2f196..a6a625be13f 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -947,6 +947,14 @@ struct lock_manager_operations {
int (*fl_change)(struct file_lock **, int);
};
+struct lock_manager {
+ struct list_head list;
+};
+
+void locks_start_grace(struct lock_manager *);
+void locks_end_grace(struct lock_manager *);
+int locks_in_grace(void);
+
/* that will die - we need it for nfs_lock_info */
#include <linux/nfs_fs_i.h>
@@ -988,6 +996,13 @@ struct file_lock {
#include <linux/fcntl.h>
+extern void send_sigio(struct fown_struct *fown, int fd, int band);
+
+/* fs/sync.c */
+extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
+ loff_t endbyte, unsigned int flags);
+
+#ifdef CONFIG_FILE_LOCKING
extern int fcntl_getlk(struct file *, struct flock __user *);
extern int fcntl_setlk(unsigned int, struct file *, unsigned int,
struct flock __user *);
@@ -998,14 +1013,9 @@ extern int fcntl_setlk64(unsigned int, struct file *, unsigned int,
struct flock64 __user *);
#endif
-extern void send_sigio(struct fown_struct *fown, int fd, int band);
extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
extern int fcntl_getlease(struct file *filp);
-/* fs/sync.c */
-extern int do_sync_mapping_range(struct address_space *mapping, loff_t offset,
- loff_t endbyte, unsigned int flags);
-
/* fs/locks.c */
extern void locks_init_lock(struct file_lock *);
extern void locks_copy_lock(struct file_lock *, struct file_lock *);
@@ -1028,6 +1038,37 @@ 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 struct seq_operations locks_seq_operations;
+#else /* !CONFIG_FILE_LOCKING */
+#define fcntl_getlk(a, b) ({ -EINVAL; })
+#define fcntl_setlk(a, b, c, d) ({ -EACCES; })
+#if BITS_PER_LONG == 32
+#define fcntl_getlk64(a, b) ({ -EINVAL; })
+#define fcntl_setlk64(a, b, c, d) ({ -EACCES; })
+#endif
+#define fcntl_setlease(a, b, c) ({ 0; })
+#define fcntl_getlease(a) ({ 0; })
+#define locks_init_lock(a) ({ })
+#define __locks_copy_lock(a, b) ({ })
+#define locks_copy_lock(a, b) ({ })
+#define locks_remove_posix(a, b) ({ })
+#define locks_remove_flock(a) ({ })
+#define posix_test_lock(a, b) ({ 0; })
+#define posix_lock_file(a, b, c) ({ -ENOLCK; })
+#define posix_lock_file_wait(a, b) ({ -ENOLCK; })
+#define posix_unblock_lock(a, b) (-ENOENT)
+#define vfs_test_lock(a, b) ({ 0; })
+#define vfs_lock_file(a, b, c, d) (-ENOLCK)
+#define vfs_cancel_lock(a, b) ({ 0; })
+#define flock_lock_file_wait(a, b) ({ -ENOLCK; })
+#define __break_lease(a, b) ({ 0; })
+#define lease_get_mtime(a, b) ({ })
+#define generic_setlease(a, b, c) ({ -EINVAL; })
+#define vfs_setlease(a, b, c) ({ -EINVAL; })
+#define lease_modify(a, b) ({ -EINVAL; })
+#define lock_may_read(a, b, c) ({ 1; })
+#define lock_may_write(a, b, c) ({ 1; })
+#endif /* !CONFIG_FILE_LOCKING */
+
struct fasync_struct {
int magic;
@@ -1575,9 +1616,12 @@ extern int vfs_statfs(struct dentry *, struct kstatfs *);
/* /sys/fs */
extern struct kobject *fs_kobj;
+extern int rw_verify_area(int, struct file *, loff_t *, size_t);
+
#define FLOCK_VERIFY_READ 1
#define FLOCK_VERIFY_WRITE 2
+#ifdef CONFIG_FILE_LOCKING
extern int locks_mandatory_locked(struct inode *);
extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
@@ -1608,8 +1652,6 @@ static inline int locks_verify_locked(struct inode *inode)
return 0;
}
-extern int rw_verify_area(int, struct file *, loff_t *, size_t);
-
static inline int locks_verify_truncate(struct inode *inode,
struct file *filp,
loff_t size)
@@ -1630,6 +1672,15 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
return __break_lease(inode, mode);
return 0;
}
+#else /* !CONFIG_FILE_LOCKING */
+#define locks_mandatory_locked(a) ({ 0; })
+#define locks_mandatory_area(a, b, c, d, e) ({ 0; })
+#define __mandatory_lock(a) ({ 0; })
+#define mandatory_lock(a) ({ 0; })
+#define locks_verify_locked(a) ({ 0; })
+#define locks_verify_truncate(a, b, c) ({ 0; })
+#define break_lease(a, b) ({ 0; })
+#endif /* CONFIG_FILE_LOCKING */
/* fs/open.c */
diff --git a/include/linux/gpio.h b/include/linux/gpio.h
index 730a20b8357..e10c49a5b96 100644
--- a/include/linux/gpio.h
+++ b/include/linux/gpio.h
@@ -8,6 +8,7 @@
#else
+#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/errno.h>
@@ -32,6 +33,8 @@ static inline int gpio_request(unsigned gpio, const char *label)
static inline void gpio_free(unsigned gpio)
{
+ might_sleep();
+
/* GPIO can never have been requested */
WARN_ON(1);
}
diff --git a/include/linux/hid.h b/include/linux/hid.h
index ac4e678a04e..f13bca2dd53 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -67,6 +67,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/list.h>
+#include <linux/mod_devicetable.h> /* hid_device_id */
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/input.h>
@@ -246,6 +247,19 @@ struct hid_item {
#define HID_FEATURE_REPORT 2
/*
+ * HID connect requests
+ */
+
+#define HID_CONNECT_HIDINPUT 0x01
+#define HID_CONNECT_HIDINPUT_FORCE 0x02
+#define HID_CONNECT_HIDRAW 0x04
+#define HID_CONNECT_HIDDEV 0x08
+#define HID_CONNECT_HIDDEV_FORCE 0x10
+#define HID_CONNECT_FF 0x20
+#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \
+ HID_CONNECT_HIDDEV|HID_CONNECT_FF)
+
+/*
* HID device quirks.
*/
@@ -256,48 +270,11 @@ struct hid_item {
#define HID_QUIRK_INVERT 0x00000001
#define HID_QUIRK_NOTOUCH 0x00000002
-#define HID_QUIRK_IGNORE 0x00000004
#define HID_QUIRK_NOGET 0x00000008
-#define HID_QUIRK_HIDDEV 0x00000010
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200
-#define HID_QUIRK_MIGHTYMOUSE 0x00000400
-#define HID_QUIRK_APPLE_HAS_FN 0x00000800
-#define HID_QUIRK_APPLE_FN_ON 0x00001000
-#define HID_QUIRK_INVERT_HWHEEL 0x00002000
-#define HID_QUIRK_APPLE_ISO_KEYBOARD 0x00004000
-#define HID_QUIRK_BAD_RELATIVE_KEYS 0x00008000
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
-#define HID_QUIRK_IGNORE_MOUSE 0x00020000
-#define HID_QUIRK_SONY_PS3_CONTROLLER 0x00040000
-#define HID_QUIRK_DUPLICATE_USAGES 0x00080000
-#define HID_QUIRK_RESET_LEDS 0x00100000
-#define HID_QUIRK_HIDINPUT 0x00200000
-#define HID_QUIRK_LOGITECH_IGNORE_DOUBLED_WHEEL 0x00400000
-#define HID_QUIRK_LOGITECH_EXPANDED_KEYMAP 0x00800000
-#define HID_QUIRK_IGNORE_HIDINPUT 0x01000000
-#define HID_QUIRK_2WHEEL_MOUSE_HACK_B8 0x02000000
-#define HID_QUIRK_HWHEEL_WHEEL_INVERT 0x04000000
-#define HID_QUIRK_MICROSOFT_KEYS 0x08000000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
-#define HID_QUIRK_APPLE_NUMLOCK_EMULATION 0x20000000
-
-/*
- * Separate quirks for runtime report descriptor fixup
- */
-
-#define HID_QUIRK_RDESC_CYMOTION 0x00000001
-#define HID_QUIRK_RDESC_LOGITECH 0x00000002
-#define HID_QUIRK_RDESC_SWAPPED_MIN_MAX 0x00000004
-#define HID_QUIRK_RDESC_PETALYNX 0x00000008
-#define HID_QUIRK_RDESC_MACBOOK_JIS 0x00000010
-#define HID_QUIRK_RDESC_BUTTON_CONSUMER 0x00000020
-#define HID_QUIRK_RDESC_SAMSUNG_REMOTE 0x00000040
-#define HID_QUIRK_RDESC_MICROSOFT_RECV_1028 0x00000080
-#define HID_QUIRK_RDESC_SUNPLUS_WDESKTOP 0x00000100
/*
* This is the global environment of the parser. This information is
@@ -411,12 +388,21 @@ struct hid_report_enum {
struct hid_control_fifo {
unsigned char dir;
struct hid_report *report;
+ char *raw_report;
+};
+
+struct hid_output_fifo {
+ struct hid_report *report;
+ char *raw_report;
};
#define HID_CLAIMED_INPUT 1
#define HID_CLAIMED_HIDDEV 2
#define HID_CLAIMED_HIDRAW 4
+#define HID_STAT_ADDED 1
+#define HID_STAT_PARSED 2
+
#define HID_CTRL_RUNNING 1
#define HID_OUT_RUNNING 2
#define HID_IN_RUNNING 3
@@ -431,22 +417,28 @@ struct hid_input {
struct input_dev *input;
};
+struct hid_driver;
+struct hid_ll_driver;
+
struct hid_device { /* device report descriptor */
- __u8 *rdesc;
+ __u8 *rdesc;
unsigned rsize;
struct hid_collection *collection; /* List of HID collections */
unsigned collection_size; /* Number of allocated hid_collections */
unsigned maxcollection; /* Number of parsed collections */
unsigned maxapplication; /* Number of applications */
- unsigned short bus; /* BUS ID */
- unsigned short vendor; /* Vendor ID */
- unsigned short product; /* Product ID */
- unsigned version; /* HID version */
+ __u16 bus; /* BUS ID */
+ __u32 vendor; /* Vendor ID */
+ __u32 product; /* Product ID */
+ __u32 version; /* HID version */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
- struct device *dev; /* device */
+ struct device dev; /* device */
+ struct hid_driver *driver;
+ struct hid_ll_driver *ll_driver;
+ unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
@@ -462,26 +454,29 @@ struct hid_device { /* device report descriptor */
void *driver_data;
- __s32 delayed_value; /* For A4 Tech mice hwheel quirk */
-
- /* device-specific function pointers */
- int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
- int (*hid_open) (struct hid_device *);
- void (*hid_close) (struct hid_device *);
+ /* temporary hid_ff handling (until moved to the drivers) */
+ int (*ff_init)(struct hid_device *);
/* hiddev event handler */
+ int (*hiddev_connect)(struct hid_device *, unsigned int);
void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
struct hid_usage *, __s32);
void (*hiddev_report_event) (struct hid_device *, struct hid_report *);
/* handler for raw output data, used by hidraw */
int (*hid_output_raw_report) (struct hid_device *, __u8 *, size_t);
-#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
- unsigned long apple_pressed_fn[BITS_TO_LONGS(KEY_CNT)];
- unsigned long pb_pressed_numlock[BITS_TO_LONGS(KEY_CNT)];
-#endif
};
+static inline void *hid_get_drvdata(struct hid_device *hdev)
+{
+ return dev_get_drvdata(&hdev->dev);
+}
+
+static inline void hid_set_drvdata(struct hid_device *hdev, void *data)
+{
+ dev_set_drvdata(&hdev->dev, data);
+}
+
#define HID_GLOBAL_STACK_SIZE 4
#define HID_COLLECTION_STACK_SIZE 4
@@ -510,6 +505,107 @@ struct hid_descriptor {
struct hid_class_descriptor desc[1];
} __attribute__ ((packed));
+#define HID_DEVICE(b, ven, prod) \
+ .bus = (b), \
+ .vendor = (ven), .product = (prod)
+
+#define HID_USB_DEVICE(ven, prod) HID_DEVICE(BUS_USB, ven, prod)
+#define HID_BLUETOOTH_DEVICE(ven, prod) HID_DEVICE(BUS_BLUETOOTH, ven, prod)
+
+#define HID_REPORT_ID(rep) \
+ .report_type = (rep)
+#define HID_USAGE_ID(uhid, utype, ucode) \
+ .usage_hid = (uhid), .usage_type = (utype), .usage_code = (ucode)
+/* we don't want to catch types and codes equal to 0 */
+#define HID_TERMINATOR (HID_ANY_ID - 1)
+
+struct hid_report_id {
+ __u32 report_type;
+};
+struct hid_usage_id {
+ __u32 usage_hid;
+ __u32 usage_type;
+ __u32 usage_code;
+};
+
+/**
+ * struct hid_driver
+ * @name: driver name (e.g. "Footech_bar-wheel")
+ * @id_table: which devices is this driver for (must be non-NULL for probe
+ * to be called)
+ * @probe: new device inserted
+ * @remove: device removed (NULL if not a hot-plug capable driver)
+ * @report_table: on which reports to call raw_event (NULL means all)
+ * @raw_event: if report in report_table, this hook is called (NULL means nop)
+ * @usage_table: on which events to call event (NULL means all)
+ * @event: if usage in usage_table, this hook is called (NULL means nop)
+ * @report_fixup: called before report descriptor parsing (NULL means nop)
+ * @input_mapping: invoked on input registering before mapping an usage
+ * @input_mapped: invoked on input registering after mapping an usage
+ *
+ * raw_event and event should return 0 on no action performed, 1 when no
+ * further processing should be done and negative on error
+ *
+ * input_mapping shall return a negative value to completely ignore this usage
+ * (e.g. doubled or invalid usage), zero to continue with parsing of this
+ * usage by generic code (no special handling needed) or positive to skip
+ * generic parsing (needed special handling which was done in the hook already)
+ * input_mapped shall return negative to inform the layer that this usage
+ * should not be considered for further processing or zero to notify that
+ * no processing was performed and should be done in a generic manner
+ * Both these functions may be NULL which means the same behavior as returning
+ * zero from them.
+ */
+struct hid_driver {
+ char *name;
+ const struct hid_device_id *id_table;
+
+ int (*probe)(struct hid_device *dev, const struct hid_device_id *id);
+ void (*remove)(struct hid_device *dev);
+
+ const struct hid_report_id *report_table;
+ int (*raw_event)(struct hid_device *hdev, struct hid_report *report,
+ u8 *data, int size);
+ const struct hid_usage_id *usage_table;
+ int (*event)(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value);
+
+ void (*report_fixup)(struct hid_device *hdev, __u8 *buf,
+ unsigned int size);
+
+ int (*input_mapping)(struct hid_device *hdev,
+ struct hid_input *hidinput, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max);
+ int (*input_mapped)(struct hid_device *hdev,
+ struct hid_input *hidinput, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max);
+/* private: */
+ struct device_driver driver;
+};
+
+/**
+ * hid_ll_driver - low level driver callbacks
+ * @start: called on probe to start the device
+ * @stop: called on remove
+ * @open: called by input layer on open
+ * @close: called by input layer on close
+ * @hidinput_input_event: event input event (e.g. ff or leds)
+ * @parse: this method is called only once to parse the device data,
+ * shouldn't allocate anything to not leak memory
+ */
+struct hid_ll_driver {
+ int (*start)(struct hid_device *hdev);
+ void (*stop)(struct hid_device *hdev);
+
+ int (*open)(struct hid_device *hdev);
+ void (*close)(struct hid_device *hdev);
+
+ int (*hidinput_input_event) (struct input_dev *idev, unsigned int type,
+ unsigned int code, int value);
+
+ int (*parse)(struct hid_device *hdev);
+};
+
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || (a == 0x000d0002))
@@ -520,43 +616,157 @@ struct hid_descriptor {
extern int hid_debug;
#endif
+extern int hid_add_device(struct hid_device *);
+extern void hid_destroy_device(struct hid_device *);
+
+extern int __must_check __hid_register_driver(struct hid_driver *,
+ struct module *, const char *mod_name);
+static inline int __must_check hid_register_driver(struct hid_driver *driver)
+{
+ return __hid_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
+}
+extern void hid_unregister_driver(struct hid_driver *);
+
extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
-extern int hidinput_connect(struct hid_device *);
+extern int hidinput_connect(struct hid_device *hid, unsigned int force);
extern void hidinput_disconnect(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *, int type, u8 *, int, int);
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
-int hidinput_mapping_quirks(struct hid_usage *, struct input_dev *, unsigned long **, int *);
-int hidinput_event_quirks(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
-int hidinput_apple_event(struct hid_device *, struct input_dev *, struct hid_usage *, __s32);
void hid_output_report(struct hid_report *report, __u8 *data);
-void hid_free_device(struct hid_device *device);
-struct hid_device *hid_parse_report(__u8 *start, unsigned size);
+struct hid_device *hid_allocate_device(void);
+int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+int hid_connect(struct hid_device *hid, unsigned int connect_mask);
+
+/**
+ * hid_map_usage - map usage input bits
+ *
+ * @hidinput: hidinput which we are interested in
+ * @usage: usage to fill in
+ * @bit: pointer to input->{}bit (out parameter)
+ * @max: maximal valid usage->code to consider later (out parameter)
+ * @type: input event type (EV_KEY, EV_REL, ...)
+ * @c: code which corresponds to this usage and type
+ */
+static inline void hid_map_usage(struct hid_input *hidinput,
+ struct hid_usage *usage, unsigned long **bit, int *max,
+ __u8 type, __u16 c)
+{
+ struct input_dev *input = hidinput->input;
+
+ usage->type = type;
+ usage->code = c;
+
+ switch (type) {
+ case EV_ABS:
+ *bit = input->absbit;
+ *max = ABS_MAX;
+ break;
+ case EV_REL:
+ *bit = input->relbit;
+ *max = REL_MAX;
+ break;
+ case EV_KEY:
+ *bit = input->keybit;
+ *max = KEY_MAX;
+ break;
+ case EV_LED:
+ *bit = input->ledbit;
+ *max = LED_MAX;
+ break;
+ }
+}
+
+/**
+ * hid_map_usage_clear - map usage input bits and clear the input bit
+ *
+ * The same as hid_map_usage, except the @c bit is also cleared in supported
+ * bits (@bit).
+ */
+static inline void hid_map_usage_clear(struct hid_input *hidinput,
+ struct hid_usage *usage, unsigned long **bit, int *max,
+ __u8 type, __u16 c)
+{
+ hid_map_usage(hidinput, usage, bit, max, type, c);
+ clear_bit(c, *bit);
+}
+
+/**
+ * hid_parse - parse HW reports
+ *
+ * @hdev: hid device
+ *
+ * Call this from probe after you set up the device (if needed). Your
+ * report_fixup will be called (if non-NULL) after reading raw report from
+ * device before passing it to hid layer for real parsing.
+ */
+static inline int __must_check hid_parse(struct hid_device *hdev)
+{
+ int ret;
+
+ if (hdev->status & HID_STAT_PARSED)
+ return 0;
+
+ ret = hdev->ll_driver->parse(hdev);
+ if (!ret)
+ hdev->status |= HID_STAT_PARSED;
+
+ return ret;
+}
+
+/**
+ * hid_hw_start - start underlaying HW
+ *
+ * @hdev: hid device
+ * @connect_mask: which outputs to connect, see HID_CONNECT_*
+ *
+ * Call this in probe function *after* hid_parse. This will setup HW buffers
+ * and start the device (if not deffered to device open). hid_hw_stop must be
+ * called if this was successfull.
+ */
+static inline int __must_check hid_hw_start(struct hid_device *hdev,
+ unsigned int connect_mask)
+{
+ int ret = hdev->ll_driver->start(hdev);
+ if (ret || !connect_mask)
+ return ret;
+ ret = hid_connect(hdev, connect_mask);
+ if (ret)
+ hdev->ll_driver->stop(hdev);
+ return ret;
+}
+
+/**
+ * hid_hw_stop - stop underlaying HW
+ *
+ * @hdev: hid device
+ *
+ * This is usually called from remove function or from probe when something
+ * failed and hid_hw_start was called already.
+ */
+static inline void hid_hw_stop(struct hid_device *hdev)
+{
+ hdev->ll_driver->stop(hdev);
+}
+
+void hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
+ int interrupt);
+
+extern int hid_generic_init(void);
+extern void hid_generic_exit(void);
/* HID quirks API */
u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct);
int usbhid_quirks_init(char **quirks_param);
void usbhid_quirks_exit(void);
-void usbhid_fixup_report_descriptor(const u16, const u16, char *, unsigned, char **);
-
-#ifdef CONFIG_HID_FF
-int hid_ff_init(struct hid_device *hid);
+void usbhid_set_leds(struct hid_device *hid);
-int hid_lgff_init(struct hid_device *hid);
-int hid_lg2ff_init(struct hid_device *hid);
-int hid_plff_init(struct hid_device *hid);
-int hid_tmff_init(struct hid_device *hid);
-int hid_zpff_init(struct hid_device *hid);
#ifdef CONFIG_HID_PID
int hid_pidff_init(struct hid_device *hid);
#else
-static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
-#endif
-
-#else
-static inline int hid_ff_init(struct hid_device *hid) { return -1; }
+#define hid_pidff_init NULL
#endif
#ifdef CONFIG_HID_DEBUG
@@ -572,10 +782,23 @@ dbg_hid(const char *fmt, ...)
return 0;
}
#define dbg_hid_line dbg_hid
-#endif
+#endif /* HID_DEBUG */
#define err_hid(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
__FILE__ , ## arg)
-#endif
+#endif /* HID_FF */
+
+#ifdef CONFIG_HID_COMPAT
+#define HID_COMPAT_LOAD_DRIVER(name) \
+void hid_compat_##name(void) { } \
+EXPORT_SYMBOL(hid_compat_##name)
+#else
+#define HID_COMPAT_LOAD_DRIVER(name)
+#endif /* HID_COMPAT */
+#define HID_COMPAT_CALL_DRIVER(name) do { \
+ extern void hid_compat_##name(void); \
+ hid_compat_##name(); \
+} while (0)
+
#endif
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index a416b904ba9..c760ae0eb6a 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -182,26 +182,28 @@ struct hiddev_usage_ref_multi {
/* To traverse the input report descriptor info for a HID device, perform the
* following:
*
- * rinfo.report_type = HID_REPORT_TYPE_INPUT;
- * rinfo.report_id = HID_REPORT_ID_FIRST;
- * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * rinfo.report_type = HID_REPORT_TYPE_INPUT;
+ * rinfo.report_id = HID_REPORT_ID_FIRST;
+ * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
*
- * while (ret >= 0) {
- * for (i = 0; i < rinfo.num_fields; i++) {
- * finfo.report_type = rinfo.report_type;
- * finfo.report_id = rinfo.report_id;
- * finfo.field_index = i;
- * ioctl(fd, HIDIOCGFIELDINFO, &finfo);
- * for (j = 0; j < finfo.maxusage; j++) {
- * uref.field_index = i;
- * uref.usage_index = j;
- * ioctl(fd, HIDIOCGUCODE, &uref);
- * ioctl(fd, HIDIOCGUSAGE, &uref);
- * }
- * }
- * rinfo.report_id |= HID_REPORT_ID_NEXT;
- * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
- * }
+ * while (ret >= 0) {
+ * for (i = 0; i < rinfo.num_fields; i++) {
+ * finfo.report_type = rinfo.report_type;
+ * finfo.report_id = rinfo.report_id;
+ * finfo.field_index = i;
+ * ioctl(fd, HIDIOCGFIELDINFO, &finfo);
+ * for (j = 0; j < finfo.maxusage; j++) {
+ * uref.report_type = rinfo.report_type;
+ * uref.report_id = rinfo.report_id;
+ * uref.field_index = i;
+ * uref.usage_index = j;
+ * ioctl(fd, HIDIOCGUCODE, &uref);
+ * ioctl(fd, HIDIOCGUSAGE, &uref);
+ * }
+ * }
+ * rinfo.report_id |= HID_REPORT_ID_NEXT;
+ * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ * }
*/
@@ -217,7 +219,7 @@ struct hid_field;
struct hid_report;
#ifdef CONFIG_USB_HIDDEV
-int hiddev_connect(struct hid_device *);
+int hiddev_connect(struct hid_device *hid, unsigned int force);
void hiddev_disconnect(struct hid_device *);
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value);
@@ -225,7 +227,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
int __init hiddev_init(void);
void hiddev_exit(void);
#else
-static inline int hiddev_connect(struct hid_device *hid) { return -1; }
+static inline int hiddev_connect(struct hid_device *hid,
+ unsigned int force)
+{ return -1; }
static inline void hiddev_disconnect(struct hid_device *hid) { }
static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value) { }
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index 75ae6d8aba4..4c4e57d1f19 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -570,7 +570,6 @@ struct i2o_controller {
#endif
spinlock_t lock; /* lock for controller
configuration */
-
void *driver_data[I2O_MAX_DRIVERS]; /* storage for drivers */
};
@@ -691,289 +690,22 @@ static inline u32 i2o_dma_high(dma_addr_t dma_addr)
};
#endif
-/**
- * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
- * @c: I2O controller for which the calculation should be done
- * @body_size: maximum body size used for message in 32-bit words.
- *
- * Return the maximum number of SG elements in a SG list.
- */
-static inline u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
-{
- i2o_status_block *sb = c->status_block.virt;
- u16 sg_count =
- (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
- body_size;
-
- if (c->pae_support) {
- /*
- * for 64-bit a SG attribute element must be added and each
- * SG element needs 12 bytes instead of 8.
- */
- sg_count -= 2;
- sg_count /= 3;
- } else
- sg_count /= 2;
-
- if (c->short_req && (sg_count > 8))
- sg_count = 8;
-
- return sg_count;
-};
-
-/**
- * i2o_dma_map_single - Map pointer to controller and fill in I2O message.
- * @c: I2O controller
- * @ptr: pointer to the data which should be mapped
- * @size: size of data in bytes
- * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- * @sg_ptr: pointer to the SG list inside the I2O message
- *
- * This function does all necessary DMA handling and also writes the I2O
- * SGL elements into the I2O message. For details on DMA handling see also
- * dma_map_single(). The pointer sg_ptr will only be set to the end of the
- * SG list if the allocation was successful.
- *
- * Returns DMA address which must be checked for failures using
- * dma_mapping_error().
- */
-static inline dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+extern u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size);
+extern dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
size_t size,
enum dma_data_direction direction,
- u32 ** sg_ptr)
-{
- u32 sg_flags;
- u32 *mptr = *sg_ptr;
- dma_addr_t dma_addr;
-
- switch (direction) {
- case DMA_TO_DEVICE:
- sg_flags = 0xd4000000;
- break;
- case DMA_FROM_DEVICE:
- sg_flags = 0xd0000000;
- break;
- default:
- return 0;
- }
-
- dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
- if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
- *mptr++ = cpu_to_le32(0x7C020002);
- *mptr++ = cpu_to_le32(PAGE_SIZE);
- }
-#endif
-
- *mptr++ = cpu_to_le32(sg_flags | size);
- *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support)
- *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
-#endif
- *sg_ptr = mptr;
- }
- return dma_addr;
-};
-
-/**
- * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
- * @c: I2O controller
- * @sg: SG list to be mapped
- * @sg_count: number of elements in the SG list
- * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- * @sg_ptr: pointer to the SG list inside the I2O message
- *
- * This function does all necessary DMA handling and also writes the I2O
- * SGL elements into the I2O message. For details on DMA handling see also
- * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
- * list if the allocation was successful.
- *
- * Returns 0 on failure or 1 on success.
- */
-static inline int i2o_dma_map_sg(struct i2o_controller *c,
+ u32 ** sg_ptr);
+extern int i2o_dma_map_sg(struct i2o_controller *c,
struct scatterlist *sg, int sg_count,
enum dma_data_direction direction,
- u32 ** sg_ptr)
-{
- u32 sg_flags;
- u32 *mptr = *sg_ptr;
-
- switch (direction) {
- case DMA_TO_DEVICE:
- sg_flags = 0x14000000;
- break;
- case DMA_FROM_DEVICE:
- sg_flags = 0x10000000;
- break;
- default:
- return 0;
- }
-
- sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
- if (!sg_count)
- return 0;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
- *mptr++ = cpu_to_le32(0x7C020002);
- *mptr++ = cpu_to_le32(PAGE_SIZE);
- }
-#endif
-
- while (sg_count-- > 0) {
- if (!sg_count)
- sg_flags |= 0xC0000000;
- *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
- *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support)
- *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
-#endif
- sg = sg_next(sg);
- }
- *sg_ptr = mptr;
-
- return 1;
-};
-
-/**
- * i2o_dma_alloc - Allocate DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should get the DMA buffer
- * @len: length of the new DMA memory
- * @gfp_mask: GFP mask
- *
- * Allocate a coherent DMA memory and write the pointers into addr.
- *
- * Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
- size_t len, gfp_t gfp_mask)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- int dma_64 = 0;
-
- if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
- dma_64 = 1;
- if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
- return -ENOMEM;
- }
-
- addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
-
- if ((sizeof(dma_addr_t) > 4) && dma_64)
- if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
- printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
-
- if (!addr->virt)
- return -ENOMEM;
-
- memset(addr->virt, 0, len);
- addr->len = len;
-
- return 0;
-};
-
-/**
- * i2o_dma_free - Free DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which contains the DMA buffer
- *
- * Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
- if (addr->virt) {
- if (addr->phys)
- dma_free_coherent(dev, addr->len, addr->virt,
- addr->phys);
- else
- kfree(addr->virt);
- addr->virt = NULL;
- }
-};
-
-/**
- * i2o_dma_realloc - Realloc DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: pointer to a i2o_dma struct DMA buffer
- * @len: new length of memory
- * @gfp_mask: GFP mask
- *
- * If there was something allocated in the addr, free it first. If len > 0
- * than try to allocate it and write the addresses back to the addr
- * structure. If len == 0 set the virtual address to NULL.
- *
- * Returns the 0 on success or negative error code on failure.
- */
-static inline int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
- size_t len, gfp_t gfp_mask)
-{
- i2o_dma_free(dev, addr);
-
- if (len)
- return i2o_dma_alloc(dev, addr, len, gfp_mask);
-
- return 0;
-};
-
-/*
- * i2o_pool_alloc - Allocate an slab cache and mempool
- * @mempool: pointer to struct i2o_pool to write data into.
- * @name: name which is used to identify cache
- * @size: size of each object
- * @min_nr: minimum number of objects
- *
- * First allocates a slab cache with name and size. Then allocates a
- * mempool which uses the slab cache for allocation and freeing.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static inline int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
- size_t size, int min_nr)
-{
- pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
- if (!pool->name)
- goto exit;
- strcpy(pool->name, name);
-
- pool->slab =
- kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!pool->slab)
- goto free_name;
-
- pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
- if (!pool->mempool)
- goto free_slab;
-
- return 0;
-
- free_slab:
- kmem_cache_destroy(pool->slab);
-
- free_name:
- kfree(pool->name);
-
- exit:
- return -ENOMEM;
-};
-
-/*
- * i2o_pool_free - Free slab cache and mempool again
- * @mempool: pointer to struct i2o_pool which should be freed
- *
- * Note that you have to return all objects to the mempool again before
- * calling i2o_pool_free().
- */
-static inline void i2o_pool_free(struct i2o_pool *pool)
-{
- mempool_destroy(pool->mempool);
- kmem_cache_destroy(pool->slab);
- kfree(pool->name);
-};
-
+ u32 ** sg_ptr);
+extern int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len);
+extern void i2o_dma_free(struct device *dev, struct i2o_dma *addr);
+extern int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
+ size_t len);
+extern int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+ size_t size, int min_nr);
+extern void i2o_pool_free(struct i2o_pool *pool);
/* I2O driver (OSM) functions */
extern int i2o_driver_register(struct i2o_driver *);
extern void i2o_driver_unregister(struct i2o_driver *);
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index bf1a53b2682..7f3c735f422 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -9,7 +9,7 @@
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
*
* This program is free software; you can redistribute it and/or
diff --git a/include/linux/if_fddi.h b/include/linux/if_fddi.h
index ae77daed6c2..45de1046dbb 100644
--- a/include/linux/if_fddi.h
+++ b/include/linux/if_fddi.h
@@ -12,7 +12,7 @@
* if_fddi.h is based on previous if_ether.h and if_tr.h work by
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
* Peter De Schrijver, <stud11@cc4.kuleuven.ac.be>
*
diff --git a/include/linux/if_hippi.h b/include/linux/if_hippi.h
index 94d31ca7d71..f0f23516bb5 100644
--- a/include/linux/if_hippi.h
+++ b/include/linux/if_hippi.h
@@ -9,7 +9,7 @@
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
- * Alan Cox, <alan@redhat.com>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
* Jes Sorensen, <Jes.Sorensen@cern.ch>
*
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 7bb3c095c15..f734a0ba069 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -2,7 +2,7 @@
* Linux NET3: Internet Group Management Protocol [IGMP]
*
* Authors:
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Extended to talk the BSD extended IGMP protocol of mrouted 3.6
*
diff --git a/include/linux/init.h b/include/linux/init.h
index 93538b696e3..ad63824460e 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -233,9 +233,6 @@ struct obs_kernel_param {
__attribute__((aligned((sizeof(long))))) \
= { __setup_str_##unique_id, fn, early }
-#define __setup_null_param(str, unique_id) \
- __setup_param(str, unique_id, NULL, 0)
-
#define __setup(str, fn) \
__setup_param(str, fn, fn, 0)
@@ -296,7 +293,6 @@ void __init parse_early_param(void);
void cleanup_module(void) __attribute__((alias(#exitfn)));
#define __setup_param(str, unique_id, fn) /* nothing */
-#define __setup_null_param(str, unique_id) /* nothing */
#define __setup(str, func) /* nothing */
#endif
diff --git a/include/linux/iommu-helper.h b/include/linux/iommu-helper.h
index a6d0586e2bf..3b068e5b567 100644
--- a/include/linux/iommu-helper.h
+++ b/include/linux/iommu-helper.h
@@ -23,4 +23,7 @@ extern unsigned long iommu_area_alloc(unsigned long *map, unsigned long size,
extern void iommu_area_free(unsigned long *map, unsigned long start,
unsigned int nr);
+extern unsigned long iommu_num_pages(unsigned long addr, unsigned long len,
+ unsigned long io_page_size);
+
#endif
diff --git a/include/linux/ioport.h b/include/linux/ioport.h
index ee9bcc6f32b..0dde77272d7 100644
--- a/include/linux/ioport.h
+++ b/include/linux/ioport.h
@@ -34,7 +34,8 @@ struct resource_list {
*/
#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */
-#define IORESOURCE_IO 0x00000100 /* Resource type */
+#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */
+#define IORESOURCE_IO 0x00000100
#define IORESOURCE_MEM 0x00000200
#define IORESOURCE_IRQ 0x00000400
#define IORESOURCE_DMA 0x00000800
@@ -126,6 +127,10 @@ static inline resource_size_t resource_size(struct resource *res)
{
return res->end - res->start + 1;
}
+static inline unsigned long resource_type(struct resource *res)
+{
+ return res->flags & IORESOURCE_TYPE_BITS;
+}
/* Convenience shorthand with allocation */
#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name))
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 07a9b52a265..7ebbcb1c9ba 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -61,7 +61,7 @@ extern u8 journal_enable_debug;
do { \
if ((n) <= journal_enable_debug) { \
printk (KERN_DEBUG "(%s, %d): %s: ", \
- __FILE__, __LINE__, __FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
printk (f, ## a); \
} \
} while (0)
@@ -984,7 +984,7 @@ extern int cleanup_journal_tail(journal_t *);
#define jbd_ENOSYS() \
do { \
- printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
+ printk (KERN_ERR "JBD unimplemented function %s\n", __func__); \
current->state = TASK_UNINTERRUPTIBLE; \
schedule(); \
} while (1)
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index d2e91ea998f..463d6f10b64 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -61,7 +61,7 @@ extern u8 jbd2_journal_enable_debug;
do { \
if ((n) <= jbd2_journal_enable_debug) { \
printk (KERN_DEBUG "(%s, %d): %s: ", \
- __FILE__, __LINE__, __FUNCTION__); \
+ __FILE__, __LINE__, __func__); \
printk (f, ## a); \
} \
} while (0)
@@ -1143,7 +1143,7 @@ extern int jbd2_cleanup_journal_tail(journal_t *);
#define jbd_ENOSYS() \
do { \
- printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
+ printk (KERN_ERR "JBD unimplemented function %s\n", __func__); \
current->state = TASK_UNINTERRUPTIBLE; \
schedule(); \
} while (1)
diff --git a/include/linux/journal-head.h b/include/linux/journal-head.h
index 8a62d1e84b9..bb70ebb6a2d 100644
--- a/include/linux/journal-head.h
+++ b/include/linux/journal-head.h
@@ -3,7 +3,7 @@
*
* buffer_head fields for JBD
*
- * 27 May 2001 Andrew Morton <akpm@digeo.com>
+ * 27 May 2001 Andrew Morton
* Created - pulled out of fs.h
*/
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index b9614488744..f3fe34391d8 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -93,12 +93,10 @@ static inline void print_symbol(const char *fmt, unsigned long addr)
}
/*
- * Pretty-print a function pointer.
- *
- * ia64 and ppc64 function pointers are really function descriptors,
- * which contain a pointer the real address.
+ * Pretty-print a function pointer. This function is deprecated.
+ * Please use the "%pF" vsprintf format instead.
*/
-static inline void print_fn_descriptor_symbol(const char *fmt, void *addr)
+static inline void __deprecated print_fn_descriptor_symbol(const char *fmt, void *addr)
{
#if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
addr = *(void **)addr;
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 75d81f157d2..e971c55f45a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -235,9 +235,10 @@ extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in
extern int panic_timeout;
extern int panic_on_oops;
extern int panic_on_unrecovered_nmi;
-extern int tainted;
extern const char *print_tainted(void);
-extern void add_taint(unsigned);
+extern void add_taint(unsigned flag);
+extern int test_taint(unsigned flag);
+extern unsigned long get_taint(void);
extern int root_mountflags;
/* Values used for system_state */
@@ -250,16 +251,16 @@ extern enum system_states {
SYSTEM_SUSPEND_DISK,
} system_state;
-#define TAINT_PROPRIETARY_MODULE (1<<0)
-#define TAINT_FORCED_MODULE (1<<1)
-#define TAINT_UNSAFE_SMP (1<<2)
-#define TAINT_FORCED_RMMOD (1<<3)
-#define TAINT_MACHINE_CHECK (1<<4)
-#define TAINT_BAD_PAGE (1<<5)
-#define TAINT_USER (1<<6)
-#define TAINT_DIE (1<<7)
-#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
-#define TAINT_WARN (1<<9)
+#define TAINT_PROPRIETARY_MODULE 0
+#define TAINT_FORCED_MODULE 1
+#define TAINT_UNSAFE_SMP 2
+#define TAINT_FORCED_RMMOD 3
+#define TAINT_MACHINE_CHECK 4
+#define TAINT_BAD_PAGE 5
+#define TAINT_USER 6
+#define TAINT_DIE 7
+#define TAINT_OVERRIDDEN_ACPI_TABLE 8
+#define TAINT_WARN 9
extern void dump_stack(void) __cold;
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index a1a91577813..92213a9194e 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -99,4 +99,7 @@ struct file;
extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
struct file **filp);
+extern int usermodehelper_disable(void);
+extern void usermodehelper_enable(void);
+
#endif /* __LINUX_KMOD_H__ */
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index 3d25bcd139d..e5872dc994c 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -27,7 +27,6 @@ struct nlmsvc_binding {
struct nfs_fh *,
struct file **);
void (*fclose)(struct file *);
- unsigned long (*get_grace_period)(void);
};
extern struct nlmsvc_binding * nlmsvc_ops;
@@ -53,15 +52,7 @@ extern void nlmclnt_done(struct nlm_host *host);
extern int nlmclnt_proc(struct nlm_host *host, int cmd,
struct file_lock *fl);
-extern int lockd_up(int proto);
+extern int lockd_up(void);
extern void lockd_down(void);
-unsigned long get_nfs_grace_period(void);
-
-#ifdef CONFIG_NFSD_V4
-unsigned long get_nfs4_grace_period(void);
-#else
-static inline unsigned long get_nfs4_grace_period(void) {return 0;}
-#endif
-
#endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index dbb87ab282e..b56d5aa9b19 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -12,6 +12,8 @@
#ifdef __KERNEL__
#include <linux/in.h>
+#include <linux/in6.h>
+#include <net/ipv6.h>
#include <linux/fs.h>
#include <linux/kref.h>
#include <linux/utsname.h>
@@ -38,8 +40,9 @@
*/
struct nlm_host {
struct hlist_node h_hash; /* doubly linked list */
- struct sockaddr_in h_addr; /* peer address */
- struct sockaddr_in h_saddr; /* our address (optional) */
+ struct sockaddr_storage h_addr; /* peer address */
+ size_t h_addrlen;
+ struct sockaddr_storage h_srcaddr; /* our address (optional) */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
char * h_name; /* remote hostname */
u32 h_version; /* interface version */
@@ -61,18 +64,56 @@ struct nlm_host {
struct list_head h_granted; /* Locks in GRANTED state */
struct list_head h_reclaim; /* Locks in RECLAIM state */
struct nsm_handle * h_nsmhandle; /* NSM status handle */
+
+ char h_addrbuf[48], /* address eyecatchers */
+ h_srcaddrbuf[48];
};
struct nsm_handle {
struct list_head sm_link;
atomic_t sm_count;
char * sm_name;
- struct sockaddr_in sm_addr;
+ struct sockaddr_storage sm_addr;
+ size_t sm_addrlen;
unsigned int sm_monitored : 1,
sm_sticky : 1; /* don't unmonitor */
+ char sm_addrbuf[48]; /* address eyecatcher */
};
/*
+ * Rigorous type checking on sockaddr type conversions
+ */
+static inline struct sockaddr_in *nlm_addr_in(const struct nlm_host *host)
+{
+ return (struct sockaddr_in *)&host->h_addr;
+}
+
+static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
+{
+ return (struct sockaddr *)&host->h_addr;
+}
+
+static inline struct sockaddr_in *nlm_srcaddr_in(const struct nlm_host *host)
+{
+ return (struct sockaddr_in *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
+{
+ return (struct sockaddr *)&host->h_srcaddr;
+}
+
+static inline struct sockaddr_in *nsm_addr_in(const struct nsm_handle *handle)
+{
+ return (struct sockaddr_in *)&handle->sm_addr;
+}
+
+static inline struct sockaddr *nsm_addr(const struct nsm_handle *handle)
+{
+ return (struct sockaddr *)&handle->sm_addr;
+}
+
+/*
* Map an fl_owner_t into a unique 32-bit "pid"
*/
struct nlm_lockowner {
@@ -166,7 +207,8 @@ int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
void nlmclnt_finish_block(struct nlm_wait *block);
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
-__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+__be32 nlmclnt_grant(const struct sockaddr *addr,
+ const struct nlm_lock *lock);
void nlmclnt_recovery(struct nlm_host *);
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
void nlmclnt_next_cookie(struct nlm_cookie *);
@@ -174,12 +216,14 @@ void nlmclnt_next_cookie(struct nlm_cookie *);
/*
* Host cache
*/
-struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
- int proto, u32 version,
+struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
+ const size_t salen,
+ const unsigned short protocol,
+ const u32 version,
+ const char *hostname);
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
const char *hostname,
- unsigned int hostname_len);
-struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *,
- unsigned int);
+ const size_t hostname_len);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);
@@ -201,7 +245,7 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
*/
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_host *, struct nlm_lock *, int,
- struct nlm_cookie *);
+ struct nlm_cookie *, int);
__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
__be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
struct nlm_host *, struct nlm_lock *,
@@ -233,15 +277,82 @@ static inline struct inode *nlmsvc_file_inode(struct nlm_file *file)
return file->f_file->f_path.dentry->d_inode;
}
+static inline int __nlm_privileged_request4(const struct sockaddr *sap)
+{
+ const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+ return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) &&
+ (ntohs(sin->sin_port) < 1024);
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+ return (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LOOPBACK) &&
+ (ntohs(sin6->sin6_port) < 1024);
+}
+#else /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+static inline int __nlm_privileged_request6(const struct sockaddr *sap)
+{
+ return 0;
+}
+#endif /* defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */
+
/*
- * Compare two host addresses (needs modifying for ipv6)
+ * Ensure incoming requests are from local privileged callers.
+ *
+ * Return TRUE if sender is local and is connecting via a privileged port;
+ * otherwise return FALSE.
*/
-static inline int nlm_cmp_addr(const struct sockaddr_in *sin1,
- const struct sockaddr_in *sin2)
+static inline int nlm_privileged_requester(const struct svc_rqst *rqstp)
{
+ const struct sockaddr *sap = svc_addr(rqstp);
+
+ switch (sap->sa_family) {
+ case AF_INET:
+ return __nlm_privileged_request4(sap);
+ case AF_INET6:
+ return __nlm_privileged_request6(sap);
+ default:
+ return 0;
+ }
+}
+
+static inline int __nlm_cmp_addr4(const struct sockaddr *sap1,
+ const struct sockaddr *sap2)
+{
+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sap1;
+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sap2;
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
}
+static inline int __nlm_cmp_addr6(const struct sockaddr *sap1,
+ const struct sockaddr *sap2)
+{
+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sap1;
+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sap2;
+ return ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr);
+}
+
+/*
+ * Compare two host addresses
+ *
+ * Return TRUE if the addresses are the same; otherwise FALSE.
+ */
+static inline int nlm_cmp_addr(const struct sockaddr *sap1,
+ const struct sockaddr *sap2)
+{
+ if (sap1->sa_family == sap2->sa_family) {
+ switch (sap1->sa_family) {
+ case AF_INET:
+ return __nlm_cmp_addr4(sap1, sap2);
+ case AF_INET6:
+ return __nlm_cmp_addr6(sap1, sap2);
+ }
+ }
+ return 0;
+}
+
/*
* Compare two NLM locks.
* When the second lock is of type F_UNLCK, this acts like a wildcard.
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index df18fa053bc..d6b3a802c04 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -81,8 +81,6 @@ struct nlm_reboot {
unsigned int len;
u32 state;
__be32 addr;
- __be32 vers;
- __be32 proto;
};
/*
diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
index ec612e66391..516d955ab8a 100644
--- a/include/linux/mfd/tmio.h
+++ b/include/linux/mfd/tmio.h
@@ -1,6 +1,8 @@
#ifndef MFD_TMIO_H
#define MFD_TMIO_H
+#include <linux/fb.h>
+
#define tmio_ioread8(addr) readb(addr)
#define tmio_ioread16(addr) readw(addr)
#define tmio_ioread16_rep(r, b, l) readsw(r, b, l)
@@ -25,4 +27,21 @@ struct tmio_nand_data {
unsigned int num_partitions;
};
+#define FBIO_TMIO_ACC_WRITE 0x7C639300
+#define FBIO_TMIO_ACC_SYNC 0x7C639301
+
+struct tmio_fb_data {
+ int (*lcd_set_power)(struct platform_device *fb_dev,
+ bool on);
+ int (*lcd_mode)(struct platform_device *fb_dev,
+ const struct fb_videomode *mode);
+ int num_modes;
+ struct fb_videomode *modes;
+
+ /* in mm: size of screen */
+ int height;
+ int width;
+};
+
+
#endif
diff --git a/include/linux/mfd/wm8350/audio.h b/include/linux/mfd/wm8350/audio.h
new file mode 100644
index 00000000000..217bb22ebb8
--- /dev/null
+++ b/include/linux/mfd/wm8350/audio.h
@@ -0,0 +1,598 @@
+/*
+ * audio.h -- Audio Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_AUDIO_H_
+#define __LINUX_MFD_WM8350_AUDIO_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_CLOCK_CONTROL_1 0x28
+#define WM8350_CLOCK_CONTROL_2 0x29
+#define WM8350_FLL_CONTROL_1 0x2A
+#define WM8350_FLL_CONTROL_2 0x2B
+#define WM8350_FLL_CONTROL_3 0x2C
+#define WM8350_FLL_CONTROL_4 0x2D
+#define WM8350_DAC_CONTROL 0x30
+#define WM8350_DAC_DIGITAL_VOLUME_L 0x32
+#define WM8350_DAC_DIGITAL_VOLUME_R 0x33
+#define WM8350_DAC_LR_RATE 0x35
+#define WM8350_DAC_CLOCK_CONTROL 0x36
+#define WM8350_DAC_MUTE 0x3A
+#define WM8350_DAC_MUTE_VOLUME 0x3B
+#define WM8350_DAC_SIDE 0x3C
+#define WM8350_ADC_CONTROL 0x40
+#define WM8350_ADC_DIGITAL_VOLUME_L 0x42
+#define WM8350_ADC_DIGITAL_VOLUME_R 0x43
+#define WM8350_ADC_DIVIDER 0x44
+#define WM8350_ADC_LR_RATE 0x46
+#define WM8350_INPUT_CONTROL 0x48
+#define WM8350_IN3_INPUT_CONTROL 0x49
+#define WM8350_MIC_BIAS_CONTROL 0x4A
+#define WM8350_OUTPUT_CONTROL 0x4C
+#define WM8350_JACK_DETECT 0x4D
+#define WM8350_ANTI_POP_CONTROL 0x4E
+#define WM8350_LEFT_INPUT_VOLUME 0x50
+#define WM8350_RIGHT_INPUT_VOLUME 0x51
+#define WM8350_LEFT_MIXER_CONTROL 0x58
+#define WM8350_RIGHT_MIXER_CONTROL 0x59
+#define WM8350_OUT3_MIXER_CONTROL 0x5C
+#define WM8350_OUT4_MIXER_CONTROL 0x5D
+#define WM8350_OUTPUT_LEFT_MIXER_VOLUME 0x60
+#define WM8350_OUTPUT_RIGHT_MIXER_VOLUME 0x61
+#define WM8350_INPUT_MIXER_VOLUME_L 0x62
+#define WM8350_INPUT_MIXER_VOLUME_R 0x63
+#define WM8350_INPUT_MIXER_VOLUME 0x64
+#define WM8350_LOUT1_VOLUME 0x68
+#define WM8350_ROUT1_VOLUME 0x69
+#define WM8350_LOUT2_VOLUME 0x6A
+#define WM8350_ROUT2_VOLUME 0x6B
+#define WM8350_BEEP_VOLUME 0x6F
+#define WM8350_AI_FORMATING 0x70
+#define WM8350_ADC_DAC_COMP 0x71
+#define WM8350_AI_ADC_CONTROL 0x72
+#define WM8350_AI_DAC_CONTROL 0x73
+#define WM8350_AIF_TEST 0x74
+#define WM8350_JACK_PIN_STATUS 0xE7
+
+/* Bit values for R08 (0x08) */
+#define WM8350_CODEC_ISEL_1_5 0 /* x1.5 */
+#define WM8350_CODEC_ISEL_1_0 1 /* x1.0 */
+#define WM8350_CODEC_ISEL_0_75 2 /* x0.75 */
+#define WM8350_CODEC_ISEL_0_5 3 /* x0.5 */
+
+#define WM8350_VMID_OFF 0
+#define WM8350_VMID_500K 1
+#define WM8350_VMID_100K 2
+#define WM8350_VMID_10K 3
+
+/*
+ * R40 (0x28) - Clock Control 1
+ */
+#define WM8350_TOCLK_RATE 0x4000
+#define WM8350_MCLK_SEL 0x0800
+#define WM8350_MCLK_DIV_MASK 0x0100
+#define WM8350_BCLK_DIV_MASK 0x00F0
+#define WM8350_OPCLK_DIV_MASK 0x0007
+
+/*
+ * R41 (0x29) - Clock Control 2
+ */
+#define WM8350_LRC_ADC_SEL 0x8000
+#define WM8350_MCLK_DIR 0x0001
+
+/*
+ * R42 (0x2A) - FLL Control 1
+ */
+#define WM8350_FLL_DITHER_WIDTH_MASK 0x3000
+#define WM8350_FLL_DITHER_HP 0x0800
+#define WM8350_FLL_OUTDIV_MASK 0x0700
+#define WM8350_FLL_RSP_RATE_MASK 0x00F0
+#define WM8350_FLL_RATE_MASK 0x0007
+
+/*
+ * R43 (0x2B) - FLL Control 2
+ */
+#define WM8350_FLL_RATIO_MASK 0xF800
+#define WM8350_FLL_N_MASK 0x03FF
+
+/*
+ * R44 (0x2C) - FLL Control 3
+ */
+#define WM8350_FLL_K_MASK 0xFFFF
+
+/*
+ * R45 (0x2D) - FLL Control 4
+ */
+#define WM8350_FLL_FRAC 0x0020
+#define WM8350_FLL_SLOW_LOCK_REF 0x0010
+#define WM8350_FLL_CLK_SRC_MASK 0x0003
+
+/*
+ * R48 (0x30) - DAC Control
+ */
+#define WM8350_DAC_MONO 0x2000
+#define WM8350_AIF_LRCLKRATE 0x1000
+#define WM8350_DEEMP_MASK 0x0030
+#define WM8350_DACL_DATINV 0x0002
+#define WM8350_DACR_DATINV 0x0001
+
+/*
+ * R50 (0x32) - DAC Digital Volume L
+ */
+#define WM8350_DAC_VU 0x0100
+#define WM8350_DACL_VOL_MASK 0x00FF
+
+/*
+ * R51 (0x33) - DAC Digital Volume R
+ */
+#define WM8350_DAC_VU 0x0100
+#define WM8350_DACR_VOL_MASK 0x00FF
+
+/*
+ * R53 (0x35) - DAC LR Rate
+ */
+#define WM8350_DACLRC_ENA 0x0800
+#define WM8350_DACLRC_RATE_MASK 0x07FF
+
+/*
+ * R54 (0x36) - DAC Clock Control
+ */
+#define WM8350_DACCLK_POL 0x0010
+#define WM8350_DAC_CLKDIV_MASK 0x0007
+
+/*
+ * R58 (0x3A) - DAC Mute
+ */
+#define WM8350_DAC_MUTE_ENA 0x4000
+
+/*
+ * R59 (0x3B) - DAC Mute Volume
+ */
+#define WM8350_DAC_MUTEMODE 0x4000
+#define WM8350_DAC_MUTERATE 0x2000
+#define WM8350_DAC_SB_FILT 0x1000
+
+/*
+ * R60 (0x3C) - DAC Side
+ */
+#define WM8350_ADC_TO_DACL_MASK 0x3000
+#define WM8350_ADC_TO_DACR_MASK 0x0C00
+
+/*
+ * R64 (0x40) - ADC Control
+ */
+#define WM8350_ADC_HPF_CUT_MASK 0x0300
+#define WM8350_ADCL_DATINV 0x0002
+#define WM8350_ADCR_DATINV 0x0001
+
+/*
+ * R66 (0x42) - ADC Digital Volume L
+ */
+#define WM8350_ADC_VU 0x0100
+#define WM8350_ADCL_VOL_MASK 0x00FF
+
+/*
+ * R67 (0x43) - ADC Digital Volume R
+ */
+#define WM8350_ADC_VU 0x0100
+#define WM8350_ADCR_VOL_MASK 0x00FF
+
+/*
+ * R68 (0x44) - ADC Divider
+ */
+#define WM8350_ADCL_DAC_SVOL_MASK 0x0F00
+#define WM8350_ADCR_DAC_SVOL_MASK 0x00F0
+#define WM8350_ADCCLK_POL 0x0008
+#define WM8350_ADC_CLKDIV_MASK 0x0007
+
+/*
+ * R70 (0x46) - ADC LR Rate
+ */
+#define WM8350_ADCLRC_ENA 0x0800
+#define WM8350_ADCLRC_RATE_MASK 0x07FF
+
+/*
+ * R72 (0x48) - Input Control
+ */
+#define WM8350_IN2R_ENA 0x0400
+#define WM8350_IN1RN_ENA 0x0200
+#define WM8350_IN1RP_ENA 0x0100
+#define WM8350_IN2L_ENA 0x0004
+#define WM8350_IN1LN_ENA 0x0002
+#define WM8350_IN1LP_ENA 0x0001
+
+/*
+ * R73 (0x49) - IN3 Input Control
+ */
+#define WM8350_IN3R_SHORT 0x4000
+#define WM8350_IN3L_SHORT 0x0040
+
+/*
+ * R74 (0x4A) - Mic Bias Control
+ */
+#define WM8350_MICBSEL 0x4000
+#define WM8350_MCDTHR_MASK 0x001C
+#define WM8350_MCDSCTHR_MASK 0x0003
+
+/*
+ * R76 (0x4C) - Output Control
+ */
+#define WM8350_OUT4_VROI 0x0800
+#define WM8350_OUT3_VROI 0x0400
+#define WM8350_OUT2_VROI 0x0200
+#define WM8350_OUT1_VROI 0x0100
+#define WM8350_OUT2_FB 0x0004
+#define WM8350_OUT1_FB 0x0001
+
+/*
+ * R77 (0x4D) - Jack Detect
+ */
+#define WM8350_JDL_ENA 0x8000
+#define WM8350_JDR_ENA 0x4000
+
+/*
+ * R78 (0x4E) - Anti Pop Control
+ */
+#define WM8350_ANTI_POP_MASK 0x0300
+#define WM8350_DIS_OP_LN4_MASK 0x00C0
+#define WM8350_DIS_OP_LN3_MASK 0x0030
+#define WM8350_DIS_OP_OUT2_MASK 0x000C
+#define WM8350_DIS_OP_OUT1_MASK 0x0003
+
+/*
+ * R80 (0x50) - Left Input Volume
+ */
+#define WM8350_INL_MUTE 0x4000
+#define WM8350_INL_ZC 0x2000
+#define WM8350_IN_VU 0x0100
+#define WM8350_INL_VOL_MASK 0x00FC
+
+/*
+ * R81 (0x51) - Right Input Volume
+ */
+#define WM8350_INR_MUTE 0x4000
+#define WM8350_INR_ZC 0x2000
+#define WM8350_IN_VU 0x0100
+#define WM8350_INR_VOL_MASK 0x00FC
+
+/*
+ * R88 (0x58) - Left Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTL 0x1000
+#define WM8350_DACL_TO_MIXOUTL 0x0800
+#define WM8350_IN3L_TO_MIXOUTL 0x0004
+#define WM8350_INR_TO_MIXOUTL 0x0002
+#define WM8350_INL_TO_MIXOUTL 0x0001
+
+/*
+ * R89 (0x59) - Right Mixer Control
+ */
+#define WM8350_DACR_TO_MIXOUTR 0x1000
+#define WM8350_DACL_TO_MIXOUTR 0x0800
+#define WM8350_IN3R_TO_MIXOUTR 0x0008
+#define WM8350_INR_TO_MIXOUTR 0x0002
+#define WM8350_INL_TO_MIXOUTR 0x0001
+
+/*
+ * R92 (0x5C) - OUT3 Mixer Control
+ */
+#define WM8350_DACL_TO_OUT3 0x0800
+#define WM8350_MIXINL_TO_OUT3 0x0100
+#define WM8350_OUT4_TO_OUT3 0x0008
+#define WM8350_MIXOUTL_TO_OUT3 0x0001
+
+/*
+ * R93 (0x5D) - OUT4 Mixer Control
+ */
+#define WM8350_DACR_TO_OUT4 0x1000
+#define WM8350_DACL_TO_OUT4 0x0800
+#define WM8350_OUT4_ATTN 0x0400
+#define WM8350_MIXINR_TO_OUT4 0x0200
+#define WM8350_OUT3_TO_OUT4 0x0004
+#define WM8350_MIXOUTR_TO_OUT4 0x0002
+#define WM8350_MIXOUTL_TO_OUT4 0x0001
+
+/*
+ * R96 (0x60) - Output Left Mixer Volume
+ */
+#define WM8350_IN3L_MIXOUTL_VOL_MASK 0x0E00
+#define WM8350_IN3L_MIXOUTL_VOL_SHIFT 9
+#define WM8350_INR_MIXOUTL_VOL_MASK 0x00E0
+#define WM8350_INR_MIXOUTL_VOL_SHIFT 5
+#define WM8350_INL_MIXOUTL_VOL_MASK 0x000E
+#define WM8350_INL_MIXOUTL_VOL_SHIFT 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3L_MIXOUTL_VOL_OFF 0
+#define WM8350_IN3L_MIXOUTL_VOL_M12DB 1
+#define WM8350_IN3L_MIXOUTL_VOL_M9DB 2
+#define WM8350_IN3L_MIXOUTL_VOL_M6DB 3
+#define WM8350_IN3L_MIXOUTL_VOL_M3DB 4
+#define WM8350_IN3L_MIXOUTL_VOL_0DB 5
+#define WM8350_IN3L_MIXOUTL_VOL_3DB 6
+#define WM8350_IN3L_MIXOUTL_VOL_6DB 7
+
+#define WM8350_INR_MIXOUTL_VOL_OFF 0
+#define WM8350_INR_MIXOUTL_VOL_M12DB 1
+#define WM8350_INR_MIXOUTL_VOL_M9DB 2
+#define WM8350_INR_MIXOUTL_VOL_M6DB 3
+#define WM8350_INR_MIXOUTL_VOL_M3DB 4
+#define WM8350_INR_MIXOUTL_VOL_0DB 5
+#define WM8350_INR_MIXOUTL_VOL_3DB 6
+#define WM8350_INR_MIXOUTL_VOL_6DB 7
+
+#define WM8350_INL_MIXOUTL_VOL_OFF 0
+#define WM8350_INL_MIXOUTL_VOL_M12DB 1
+#define WM8350_INL_MIXOUTL_VOL_M9DB 2
+#define WM8350_INL_MIXOUTL_VOL_M6DB 3
+#define WM8350_INL_MIXOUTL_VOL_M3DB 4
+#define WM8350_INL_MIXOUTL_VOL_0DB 5
+#define WM8350_INL_MIXOUTL_VOL_3DB 6
+#define WM8350_INL_MIXOUTL_VOL_6DB 7
+
+/*
+ * R97 (0x61) - Output Right Mixer Volume
+ */
+#define WM8350_IN3R_MIXOUTR_VOL_MASK 0xE000
+#define WM8350_IN3R_MIXOUTR_VOL_SHIFT 13
+#define WM8350_INR_MIXOUTR_VOL_MASK 0x00E0
+#define WM8350_INR_MIXOUTR_VOL_SHIFT 5
+#define WM8350_INL_MIXOUTR_VOL_MASK 0x000E
+#define WM8350_INL_MIXOUTR_VOL_SHIFT 1
+
+/* Bit values for R96 (0x60) */
+#define WM8350_IN3R_MIXOUTR_VOL_OFF 0
+#define WM8350_IN3R_MIXOUTR_VOL_M12DB 1
+#define WM8350_IN3R_MIXOUTR_VOL_M9DB 2
+#define WM8350_IN3R_MIXOUTR_VOL_M6DB 3
+#define WM8350_IN3R_MIXOUTR_VOL_M3DB 4
+#define WM8350_IN3R_MIXOUTR_VOL_0DB 5
+#define WM8350_IN3R_MIXOUTR_VOL_3DB 6
+#define WM8350_IN3R_MIXOUTR_VOL_6DB 7
+
+#define WM8350_INR_MIXOUTR_VOL_OFF 0
+#define WM8350_INR_MIXOUTR_VOL_M12DB 1
+#define WM8350_INR_MIXOUTR_VOL_M9DB 2
+#define WM8350_INR_MIXOUTR_VOL_M6DB 3
+#define WM8350_INR_MIXOUTR_VOL_M3DB 4
+#define WM8350_INR_MIXOUTR_VOL_0DB 5
+#define WM8350_INR_MIXOUTR_VOL_3DB 6
+#define WM8350_INR_MIXOUTR_VOL_6DB 7
+
+#define WM8350_INL_MIXOUTR_VOL_OFF 0
+#define WM8350_INL_MIXOUTR_VOL_M12DB 1
+#define WM8350_INL_MIXOUTR_VOL_M9DB 2
+#define WM8350_INL_MIXOUTR_VOL_M6DB 3
+#define WM8350_INL_MIXOUTR_VOL_M3DB 4
+#define WM8350_INL_MIXOUTR_VOL_0DB 5
+#define WM8350_INL_MIXOUTR_VOL_3DB 6
+#define WM8350_INL_MIXOUTR_VOL_6DB 7
+
+/*
+ * R98 (0x62) - Input Mixer Volume L
+ */
+#define WM8350_IN3L_MIXINL_VOL_MASK 0x0E00
+#define WM8350_IN2L_MIXINL_VOL_MASK 0x000E
+#define WM8350_INL_MIXINL_VOL 0x0001
+
+/*
+ * R99 (0x63) - Input Mixer Volume R
+ */
+#define WM8350_IN3R_MIXINR_VOL_MASK 0xE000
+#define WM8350_IN2R_MIXINR_VOL_MASK 0x00E0
+#define WM8350_INR_MIXINR_VOL 0x0001
+
+/*
+ * R100 (0x64) - Input Mixer Volume
+ */
+#define WM8350_OUT4_MIXIN_DST 0x8000
+#define WM8350_OUT4_MIXIN_VOL_MASK 0x000E
+
+/*
+ * R104 (0x68) - LOUT1 Volume
+ */
+#define WM8350_OUT1L_MUTE 0x4000
+#define WM8350_OUT1L_ZC 0x2000
+#define WM8350_OUT1_VU 0x0100
+#define WM8350_OUT1L_VOL_MASK 0x00FC
+#define WM8350_OUT1L_VOL_SHIFT 2
+
+/*
+ * R105 (0x69) - ROUT1 Volume
+ */
+#define WM8350_OUT1R_MUTE 0x4000
+#define WM8350_OUT1R_ZC 0x2000
+#define WM8350_OUT1_VU 0x0100
+#define WM8350_OUT1R_VOL_MASK 0x00FC
+#define WM8350_OUT1R_VOL_SHIFT 2
+
+/*
+ * R106 (0x6A) - LOUT2 Volume
+ */
+#define WM8350_OUT2L_MUTE 0x4000
+#define WM8350_OUT2L_ZC 0x2000
+#define WM8350_OUT2_VU 0x0100
+#define WM8350_OUT2L_VOL_MASK 0x00FC
+
+/*
+ * R107 (0x6B) - ROUT2 Volume
+ */
+#define WM8350_OUT2R_MUTE 0x4000
+#define WM8350_OUT2R_ZC 0x2000
+#define WM8350_OUT2R_INV 0x0400
+#define WM8350_OUT2R_INV_MUTE 0x0200
+#define WM8350_OUT2_VU 0x0100
+#define WM8350_OUT2R_VOL_MASK 0x00FC
+
+/*
+ * R111 (0x6F) - BEEP Volume
+ */
+#define WM8350_IN3R_OUT2R_VOL_MASK 0x00E0
+
+/*
+ * R112 (0x70) - AI Formating
+ */
+#define WM8350_AIF_BCLK_INV 0x8000
+#define WM8350_AIF_TRI 0x2000
+#define WM8350_AIF_LRCLK_INV 0x1000
+#define WM8350_AIF_WL_MASK 0x0C00
+#define WM8350_AIF_FMT_MASK 0x0300
+
+/*
+ * R113 (0x71) - ADC DAC COMP
+ */
+#define WM8350_DAC_COMP 0x0080
+#define WM8350_DAC_COMPMODE 0x0040
+#define WM8350_ADC_COMP 0x0020
+#define WM8350_ADC_COMPMODE 0x0010
+#define WM8350_LOOPBACK 0x0001
+
+/*
+ * R114 (0x72) - AI ADC Control
+ */
+#define WM8350_AIFADC_PD 0x0080
+#define WM8350_AIFADCL_SRC 0x0040
+#define WM8350_AIFADCR_SRC 0x0020
+#define WM8350_AIFADC_TDM_CHAN 0x0010
+#define WM8350_AIFADC_TDM 0x0008
+
+/*
+ * R115 (0x73) - AI DAC Control
+ */
+#define WM8350_BCLK_MSTR 0x4000
+#define WM8350_AIFDAC_PD 0x0080
+#define WM8350_DACL_SRC 0x0040
+#define WM8350_DACR_SRC 0x0020
+#define WM8350_AIFDAC_TDM_CHAN 0x0010
+#define WM8350_AIFDAC_TDM 0x0008
+#define WM8350_DAC_BOOST_MASK 0x0003
+
+/*
+ * R116 (0x74) - AIF Test
+ */
+#define WM8350_CODEC_BYP 0x4000
+#define WM8350_AIFADC_WR_TST 0x2000
+#define WM8350_AIFADC_RD_TST 0x1000
+#define WM8350_AIFDAC_WR_TST 0x0800
+#define WM8350_AIFDAC_RD_TST 0x0400
+#define WM8350_AIFADC_ASYN 0x0020
+#define WM8350_AIFDAC_ASYN 0x0010
+
+/*
+ * R231 (0xE7) - Jack Status
+ */
+#define WM8350_JACK_R_LVL 0x0400
+
+/*
+ * WM8350 Platform setup
+ */
+#define WM8350_S_CURVE_NONE 0x0
+#define WM8350_S_CURVE_FAST 0x1
+#define WM8350_S_CURVE_MEDIUM 0x2
+#define WM8350_S_CURVE_SLOW 0x3
+
+#define WM8350_DISCHARGE_OFF 0x0
+#define WM8350_DISCHARGE_FAST 0x1
+#define WM8350_DISCHARGE_MEDIUM 0x2
+#define WM8350_DISCHARGE_SLOW 0x3
+
+#define WM8350_TIE_OFF_500R 0x0
+#define WM8350_TIE_OFF_30K 0x1
+
+/*
+ * Clock sources & directions
+ */
+#define WM8350_SYSCLK 0
+
+#define WM8350_MCLK_SEL_PLL_MCLK 0
+#define WM8350_MCLK_SEL_PLL_DAC 1
+#define WM8350_MCLK_SEL_PLL_ADC 2
+#define WM8350_MCLK_SEL_PLL_32K 3
+#define WM8350_MCLK_SEL_MCLK 5
+
+#define WM8350_MCLK_DIR_OUT 0
+#define WM8350_MCLK_DIR_IN 1
+
+/* clock divider id's */
+#define WM8350_ADC_CLKDIV 0
+#define WM8350_DAC_CLKDIV 1
+#define WM8350_BCLK_CLKDIV 2
+#define WM8350_OPCLK_CLKDIV 3
+#define WM8350_TO_CLKDIV 4
+#define WM8350_SYS_CLKDIV 5
+#define WM8350_DACLR_CLKDIV 6
+#define WM8350_ADCLR_CLKDIV 7
+
+/* ADC clock dividers */
+#define WM8350_ADCDIV_1 0x0
+#define WM8350_ADCDIV_1_5 0x1
+#define WM8350_ADCDIV_2 0x2
+#define WM8350_ADCDIV_3 0x3
+#define WM8350_ADCDIV_4 0x4
+#define WM8350_ADCDIV_5_5 0x5
+#define WM8350_ADCDIV_6 0x6
+
+/* ADC clock dividers */
+#define WM8350_DACDIV_1 0x0
+#define WM8350_DACDIV_1_5 0x1
+#define WM8350_DACDIV_2 0x2
+#define WM8350_DACDIV_3 0x3
+#define WM8350_DACDIV_4 0x4
+#define WM8350_DACDIV_5_5 0x5
+#define WM8350_DACDIV_6 0x6
+
+/* BCLK clock dividers */
+#define WM8350_BCLK_DIV_1 (0x0 << 4)
+#define WM8350_BCLK_DIV_1_5 (0x1 << 4)
+#define WM8350_BCLK_DIV_2 (0x2 << 4)
+#define WM8350_BCLK_DIV_3 (0x3 << 4)
+#define WM8350_BCLK_DIV_4 (0x4 << 4)
+#define WM8350_BCLK_DIV_5_5 (0x5 << 4)
+#define WM8350_BCLK_DIV_6 (0x6 << 4)
+#define WM8350_BCLK_DIV_8 (0x7 << 4)
+#define WM8350_BCLK_DIV_11 (0x8 << 4)
+#define WM8350_BCLK_DIV_12 (0x9 << 4)
+#define WM8350_BCLK_DIV_16 (0xa << 4)
+#define WM8350_BCLK_DIV_22 (0xb << 4)
+#define WM8350_BCLK_DIV_24 (0xc << 4)
+#define WM8350_BCLK_DIV_32 (0xd << 4)
+#define WM8350_BCLK_DIV_44 (0xe << 4)
+#define WM8350_BCLK_DIV_48 (0xf << 4)
+
+/* Sys (MCLK) clock dividers */
+#define WM8350_MCLK_DIV_1 (0x0 << 8)
+#define WM8350_MCLK_DIV_2 (0x1 << 8)
+
+/* OP clock dividers */
+#define WM8350_OPCLK_DIV_1 0x0
+#define WM8350_OPCLK_DIV_2 0x1
+#define WM8350_OPCLK_DIV_3 0x2
+#define WM8350_OPCLK_DIV_4 0x3
+#define WM8350_OPCLK_DIV_5_5 0x4
+#define WM8350_OPCLK_DIV_6 0x5
+
+/* DAI ID */
+#define WM8350_HIFI_DAI 0
+
+/*
+ * Audio interrupts.
+ */
+#define WM8350_IRQ_CODEC_JCK_DET_L 39
+#define WM8350_IRQ_CODEC_JCK_DET_R 40
+#define WM8350_IRQ_CODEC_MICSCD 41
+#define WM8350_IRQ_CODEC_MICD 42
+
+struct wm8350_codec {
+ struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/comparator.h b/include/linux/mfd/wm8350/comparator.h
new file mode 100644
index 00000000000..05378864945
--- /dev/null
+++ b/include/linux/mfd/wm8350/comparator.h
@@ -0,0 +1,167 @@
+/*
+ * comparator.h -- Comparator Aux ADC for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_COMPARATOR_H_
+#define __LINUX_MFD_WM8350_COMPARATOR_H_
+
+/*
+ * Registers
+ */
+
+#define WM8350_DIGITISER_CONTROL_1 0x90
+#define WM8350_DIGITISER_CONTROL_2 0x91
+#define WM8350_AUX1_READBACK 0x98
+#define WM8350_AUX2_READBACK 0x99
+#define WM8350_AUX3_READBACK 0x9A
+#define WM8350_AUX4_READBACK 0x9B
+#define WM8350_CHIP_TEMP_READBACK 0x9F
+#define WM8350_GENERIC_COMPARATOR_CONTROL 0xA3
+#define WM8350_GENERIC_COMPARATOR_1 0xA4
+#define WM8350_GENERIC_COMPARATOR_2 0xA5
+#define WM8350_GENERIC_COMPARATOR_3 0xA6
+#define WM8350_GENERIC_COMPARATOR_4 0xA7
+
+/*
+ * R144 (0x90) - Digitiser Control (1)
+ */
+#define WM8350_AUXADC_CTC 0x4000
+#define WM8350_AUXADC_POLL 0x2000
+#define WM8350_AUXADC_HIB_MODE 0x1000
+#define WM8350_AUXADC_SEL8 0x0080
+#define WM8350_AUXADC_SEL7 0x0040
+#define WM8350_AUXADC_SEL6 0x0020
+#define WM8350_AUXADC_SEL5 0x0010
+#define WM8350_AUXADC_SEL4 0x0008
+#define WM8350_AUXADC_SEL3 0x0004
+#define WM8350_AUXADC_SEL2 0x0002
+#define WM8350_AUXADC_SEL1 0x0001
+
+/*
+ * R145 (0x91) - Digitiser Control (2)
+ */
+#define WM8350_AUXADC_MASKMODE_MASK 0x3000
+#define WM8350_AUXADC_CRATE_MASK 0x0700
+#define WM8350_AUXADC_CAL 0x0004
+#define WM8350_AUX_RBMODE 0x0002
+#define WM8350_AUXADC_WAIT 0x0001
+
+/*
+ * R152 (0x98) - AUX1 Readback
+ */
+#define WM8350_AUXADC_SCALE1_MASK 0x6000
+#define WM8350_AUXADC_REF1 0x1000
+#define WM8350_AUXADC_DATA1_MASK 0x0FFF
+
+/*
+ * R153 (0x99) - AUX2 Readback
+ */
+#define WM8350_AUXADC_SCALE2_MASK 0x6000
+#define WM8350_AUXADC_REF2 0x1000
+#define WM8350_AUXADC_DATA2_MASK 0x0FFF
+
+/*
+ * R154 (0x9A) - AUX3 Readback
+ */
+#define WM8350_AUXADC_SCALE3_MASK 0x6000
+#define WM8350_AUXADC_REF3 0x1000
+#define WM8350_AUXADC_DATA3_MASK 0x0FFF
+
+/*
+ * R155 (0x9B) - AUX4 Readback
+ */
+#define WM8350_AUXADC_SCALE4_MASK 0x6000
+#define WM8350_AUXADC_REF4 0x1000
+#define WM8350_AUXADC_DATA4_MASK 0x0FFF
+
+/*
+ * R156 (0x9C) - USB Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_USB_MASK 0x0FFF
+
+/*
+ * R157 (0x9D) - LINE Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_LINE_MASK 0x0FFF
+
+/*
+ * R158 (0x9E) - BATT Voltage Readback
+ */
+#define WM8350_AUXADC_DATA_BATT_MASK 0x0FFF
+
+/*
+ * R159 (0x9F) - Chip Temp Readback
+ */
+#define WM8350_AUXADC_DATA_CHIPTEMP_MASK 0x0FFF
+
+/*
+ * R163 (0xA3) - Generic Comparator Control
+ */
+#define WM8350_DCMP4_ENA 0x0008
+#define WM8350_DCMP3_ENA 0x0004
+#define WM8350_DCMP2_ENA 0x0002
+#define WM8350_DCMP1_ENA 0x0001
+
+/*
+ * R164 (0xA4) - Generic comparator 1
+ */
+#define WM8350_DCMP1_SRCSEL_MASK 0xE000
+#define WM8350_DCMP1_GT 0x1000
+#define WM8350_DCMP1_THR_MASK 0x0FFF
+
+/*
+ * R165 (0xA5) - Generic comparator 2
+ */
+#define WM8350_DCMP2_SRCSEL_MASK 0xE000
+#define WM8350_DCMP2_GT 0x1000
+#define WM8350_DCMP2_THR_MASK 0x0FFF
+
+/*
+ * R166 (0xA6) - Generic comparator 3
+ */
+#define WM8350_DCMP3_SRCSEL_MASK 0xE000
+#define WM8350_DCMP3_GT 0x1000
+#define WM8350_DCMP3_THR_MASK 0x0FFF
+
+/*
+ * R167 (0xA7) - Generic comparator 4
+ */
+#define WM8350_DCMP4_SRCSEL_MASK 0xE000
+#define WM8350_DCMP4_GT 0x1000
+#define WM8350_DCMP4_THR_MASK 0x0FFF
+
+/*
+ * Interrupts.
+ */
+#define WM8350_IRQ_AUXADC_DATARDY 16
+#define WM8350_IRQ_AUXADC_DCOMP4 17
+#define WM8350_IRQ_AUXADC_DCOMP3 18
+#define WM8350_IRQ_AUXADC_DCOMP2 19
+#define WM8350_IRQ_AUXADC_DCOMP1 20
+#define WM8350_IRQ_SYS_HYST_COMP_FAIL 21
+#define WM8350_IRQ_SYS_CHIP_GT115 22
+#define WM8350_IRQ_SYS_CHIP_GT140 23
+
+/*
+ * USB/2, LINE & BATT = ((VRTC * 2) / 4095)) * 10e6 uV
+ * Where VRTC = 2.7 V
+ */
+#define WM8350_AUX_COEFF 1319
+
+#define WM8350_AUXADC_AUX1 0
+#define WM8350_AUXADC_AUX2 1
+#define WM8350_AUXADC_AUX3 2
+#define WM8350_AUXADC_AUX4 3
+#define WM8350_AUXADC_USB 4
+#define WM8350_AUXADC_LINE 5
+#define WM8350_AUXADC_BATT 6
+#define WM8350_AUXADC_TEMP 7
+
+#endif
diff --git a/include/linux/mfd/wm8350/core.h b/include/linux/mfd/wm8350/core.h
new file mode 100644
index 00000000000..6ebf97f2a47
--- /dev/null
+++ b/include/linux/mfd/wm8350/core.h
@@ -0,0 +1,631 @@
+/*
+ * core.h -- Core Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_CORE_H_
+#define __LINUX_MFD_WM8350_CORE_H_
+
+#include <linux/kernel.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+
+#include <linux/mfd/wm8350/audio.h>
+#include <linux/mfd/wm8350/gpio.h>
+#include <linux/mfd/wm8350/pmic.h>
+#include <linux/mfd/wm8350/rtc.h>
+#include <linux/mfd/wm8350/supply.h>
+#include <linux/mfd/wm8350/wdt.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RESET_ID 0x00
+#define WM8350_ID 0x01
+#define WM8350_SYSTEM_CONTROL_1 0x03
+#define WM8350_SYSTEM_CONTROL_2 0x04
+#define WM8350_SYSTEM_HIBERNATE 0x05
+#define WM8350_INTERFACE_CONTROL 0x06
+#define WM8350_POWER_MGMT_1 0x08
+#define WM8350_POWER_MGMT_2 0x09
+#define WM8350_POWER_MGMT_3 0x0A
+#define WM8350_POWER_MGMT_4 0x0B
+#define WM8350_POWER_MGMT_5 0x0C
+#define WM8350_POWER_MGMT_6 0x0D
+#define WM8350_POWER_MGMT_7 0x0E
+
+#define WM8350_SYSTEM_INTERRUPTS 0x18
+#define WM8350_INT_STATUS_1 0x19
+#define WM8350_INT_STATUS_2 0x1A
+#define WM8350_POWER_UP_INT_STATUS 0x1B
+#define WM8350_UNDER_VOLTAGE_INT_STATUS 0x1C
+#define WM8350_OVER_CURRENT_INT_STATUS 0x1D
+#define WM8350_GPIO_INT_STATUS 0x1E
+#define WM8350_COMPARATOR_INT_STATUS 0x1F
+#define WM8350_SYSTEM_INTERRUPTS_MASK 0x20
+#define WM8350_INT_STATUS_1_MASK 0x21
+#define WM8350_INT_STATUS_2_MASK 0x22
+#define WM8350_POWER_UP_INT_STATUS_MASK 0x23
+#define WM8350_UNDER_VOLTAGE_INT_STATUS_MASK 0x24
+#define WM8350_OVER_CURRENT_INT_STATUS_MASK 0x25
+#define WM8350_GPIO_INT_STATUS_MASK 0x26
+#define WM8350_COMPARATOR_INT_STATUS_MASK 0x27
+
+#define WM8350_MAX_REGISTER 0xFF
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8350_SW_RESET_CHIP_ID_MASK 0xFFFF
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8350_CHIP_REV_MASK 0x7000
+#define WM8350_CONF_STS_MASK 0x0C00
+#define WM8350_CUST_ID_MASK 0x00FF
+
+/*
+ * R3 (0x03) - System Control 1
+ */
+#define WM8350_CHIP_ON 0x8000
+#define WM8350_POWERCYCLE 0x2000
+#define WM8350_VCC_FAULT_OV 0x1000
+#define WM8350_REG_RSTB_TIME_MASK 0x0C00
+#define WM8350_BG_SLEEP 0x0200
+#define WM8350_MEM_VALID 0x0020
+#define WM8350_CHIP_SET_UP 0x0010
+#define WM8350_ON_DEB_T 0x0008
+#define WM8350_ON_POL 0x0002
+#define WM8350_IRQ_POL 0x0001
+
+/*
+ * R4 (0x04) - System Control 2
+ */
+#define WM8350_USB_SUSPEND_8MA 0x8000
+#define WM8350_USB_SUSPEND 0x4000
+#define WM8350_USB_MSTR 0x2000
+#define WM8350_USB_MSTR_SRC 0x1000
+#define WM8350_USB_500MA 0x0800
+#define WM8350_USB_NOLIM 0x0400
+
+/*
+ * R5 (0x05) - System Hibernate
+ */
+#define WM8350_HIBERNATE 0x8000
+#define WM8350_WDOG_HIB_MODE 0x0080
+#define WM8350_REG_HIB_STARTUP_SEQ 0x0040
+#define WM8350_REG_RESET_HIB_MODE 0x0020
+#define WM8350_RST_HIB_MODE 0x0010
+#define WM8350_IRQ_HIB_MODE 0x0008
+#define WM8350_MEMRST_HIB_MODE 0x0004
+#define WM8350_PCCOMP_HIB_MODE 0x0002
+#define WM8350_TEMPMON_HIB_MODE 0x0001
+
+/*
+ * R6 (0x06) - Interface Control
+ */
+#define WM8350_USE_DEV_PINS 0x8000
+#define WM8350_USE_DEV_PINS_MASK 0x8000
+#define WM8350_USE_DEV_PINS_SHIFT 15
+#define WM8350_DEV_ADDR_MASK 0x6000
+#define WM8350_DEV_ADDR_SHIFT 13
+#define WM8350_CONFIG_DONE 0x1000
+#define WM8350_CONFIG_DONE_MASK 0x1000
+#define WM8350_CONFIG_DONE_SHIFT 12
+#define WM8350_RECONFIG_AT_ON 0x0800
+#define WM8350_RECONFIG_AT_ON_MASK 0x0800
+#define WM8350_RECONFIG_AT_ON_SHIFT 11
+#define WM8350_AUTOINC 0x0200
+#define WM8350_AUTOINC_MASK 0x0200
+#define WM8350_AUTOINC_SHIFT 9
+#define WM8350_ARA 0x0100
+#define WM8350_ARA_MASK 0x0100
+#define WM8350_ARA_SHIFT 8
+#define WM8350_SPI_CFG 0x0008
+#define WM8350_SPI_CFG_MASK 0x0008
+#define WM8350_SPI_CFG_SHIFT 3
+#define WM8350_SPI_4WIRE 0x0004
+#define WM8350_SPI_4WIRE_MASK 0x0004
+#define WM8350_SPI_4WIRE_SHIFT 2
+#define WM8350_SPI_3WIRE 0x0002
+#define WM8350_SPI_3WIRE_MASK 0x0002
+#define WM8350_SPI_3WIRE_SHIFT 1
+
+/* Bit values for R06 (0x06) */
+#define WM8350_USE_DEV_PINS_PRIMARY 0
+#define WM8350_USE_DEV_PINS_DEV 1
+
+#define WM8350_DEV_ADDR_34 0
+#define WM8350_DEV_ADDR_36 1
+#define WM8350_DEV_ADDR_3C 2
+#define WM8350_DEV_ADDR_3E 3
+
+#define WM8350_CONFIG_DONE_OFF 0
+#define WM8350_CONFIG_DONE_DONE 1
+
+#define WM8350_RECONFIG_AT_ON_OFF 0
+#define WM8350_RECONFIG_AT_ON_ON 1
+
+#define WM8350_AUTOINC_OFF 0
+#define WM8350_AUTOINC_ON 1
+
+#define WM8350_ARA_OFF 0
+#define WM8350_ARA_ON 1
+
+#define WM8350_SPI_CFG_CMOS 0
+#define WM8350_SPI_CFG_OD 1
+
+#define WM8350_SPI_4WIRE_3WIRE 0
+#define WM8350_SPI_4WIRE_4WIRE 1
+
+#define WM8350_SPI_3WIRE_I2C 0
+#define WM8350_SPI_3WIRE_SPI 1
+
+/*
+ * R8 (0x08) - Power mgmt (1)
+ */
+#define WM8350_CODEC_ISEL_MASK 0xC000
+#define WM8350_VBUFEN 0x2000
+#define WM8350_OUTPUT_DRAIN_EN 0x0400
+#define WM8350_MIC_DET_ENA 0x0100
+#define WM8350_BIASEN 0x0020
+#define WM8350_MICBEN 0x0010
+#define WM8350_VMIDEN 0x0004
+#define WM8350_VMID_MASK 0x0003
+#define WM8350_VMID_SHIFT 0
+
+/*
+ * R9 (0x09) - Power mgmt (2)
+ */
+#define WM8350_IN3R_ENA 0x0800
+#define WM8350_IN3L_ENA 0x0400
+#define WM8350_INR_ENA 0x0200
+#define WM8350_INL_ENA 0x0100
+#define WM8350_MIXINR_ENA 0x0080
+#define WM8350_MIXINL_ENA 0x0040
+#define WM8350_OUT4_ENA 0x0020
+#define WM8350_OUT3_ENA 0x0010
+#define WM8350_MIXOUTR_ENA 0x0002
+#define WM8350_MIXOUTL_ENA 0x0001
+
+/*
+ * R10 (0x0A) - Power mgmt (3)
+ */
+#define WM8350_IN3R_TO_OUT2R 0x0080
+#define WM8350_OUT2R_ENA 0x0008
+#define WM8350_OUT2L_ENA 0x0004
+#define WM8350_OUT1R_ENA 0x0002
+#define WM8350_OUT1L_ENA 0x0001
+
+/*
+ * R11 (0x0B) - Power mgmt (4)
+ */
+#define WM8350_SYSCLK_ENA 0x4000
+#define WM8350_ADC_HPF_ENA 0x2000
+#define WM8350_FLL_ENA 0x0800
+#define WM8350_FLL_OSC_ENA 0x0400
+#define WM8350_TOCLK_ENA 0x0100
+#define WM8350_DACR_ENA 0x0020
+#define WM8350_DACL_ENA 0x0010
+#define WM8350_ADCR_ENA 0x0008
+#define WM8350_ADCL_ENA 0x0004
+
+/*
+ * R12 (0x0C) - Power mgmt (5)
+ */
+#define WM8350_CODEC_ENA 0x1000
+#define WM8350_RTC_TICK_ENA 0x0800
+#define WM8350_OSC32K_ENA 0x0400
+#define WM8350_CHG_ENA 0x0200
+#define WM8350_ACC_DET_ENA 0x0100
+#define WM8350_AUXADC_ENA 0x0080
+#define WM8350_DCMP4_ENA 0x0008
+#define WM8350_DCMP3_ENA 0x0004
+#define WM8350_DCMP2_ENA 0x0002
+#define WM8350_DCMP1_ENA 0x0001
+
+/*
+ * R13 (0x0D) - Power mgmt (6)
+ */
+#define WM8350_LS_ENA 0x8000
+#define WM8350_LDO4_ENA 0x0800
+#define WM8350_LDO3_ENA 0x0400
+#define WM8350_LDO2_ENA 0x0200
+#define WM8350_LDO1_ENA 0x0100
+#define WM8350_DC6_ENA 0x0020
+#define WM8350_DC5_ENA 0x0010
+#define WM8350_DC4_ENA 0x0008
+#define WM8350_DC3_ENA 0x0004
+#define WM8350_DC2_ENA 0x0002
+#define WM8350_DC1_ENA 0x0001
+
+/*
+ * R14 (0x0E) - Power mgmt (7)
+ */
+#define WM8350_CS2_ENA 0x0002
+#define WM8350_CS1_ENA 0x0001
+
+/*
+ * R24 (0x18) - System Interrupts
+ */
+#define WM8350_OC_INT 0x2000
+#define WM8350_UV_INT 0x1000
+#define WM8350_PUTO_INT 0x0800
+#define WM8350_CS_INT 0x0200
+#define WM8350_EXT_INT 0x0100
+#define WM8350_CODEC_INT 0x0080
+#define WM8350_GP_INT 0x0040
+#define WM8350_AUXADC_INT 0x0020
+#define WM8350_RTC_INT 0x0010
+#define WM8350_SYS_INT 0x0008
+#define WM8350_CHG_INT 0x0004
+#define WM8350_USB_INT 0x0002
+#define WM8350_WKUP_INT 0x0001
+
+/*
+ * R25 (0x19) - Interrupt Status 1
+ */
+#define WM8350_CHG_BAT_HOT_EINT 0x8000
+#define WM8350_CHG_BAT_COLD_EINT 0x4000
+#define WM8350_CHG_BAT_FAIL_EINT 0x2000
+#define WM8350_CHG_TO_EINT 0x1000
+#define WM8350_CHG_END_EINT 0x0800
+#define WM8350_CHG_START_EINT 0x0400
+#define WM8350_CHG_FAST_RDY_EINT 0x0200
+#define WM8350_RTC_PER_EINT 0x0080
+#define WM8350_RTC_SEC_EINT 0x0040
+#define WM8350_RTC_ALM_EINT 0x0020
+#define WM8350_CHG_VBATT_LT_3P9_EINT 0x0004
+#define WM8350_CHG_VBATT_LT_3P1_EINT 0x0002
+#define WM8350_CHG_VBATT_LT_2P85_EINT 0x0001
+
+/*
+ * R26 (0x1A) - Interrupt Status 2
+ */
+#define WM8350_CS1_EINT 0x2000
+#define WM8350_CS2_EINT 0x1000
+#define WM8350_USB_LIMIT_EINT 0x0400
+#define WM8350_AUXADC_DATARDY_EINT 0x0100
+#define WM8350_AUXADC_DCOMP4_EINT 0x0080
+#define WM8350_AUXADC_DCOMP3_EINT 0x0040
+#define WM8350_AUXADC_DCOMP2_EINT 0x0020
+#define WM8350_AUXADC_DCOMP1_EINT 0x0010
+#define WM8350_SYS_HYST_COMP_FAIL_EINT 0x0008
+#define WM8350_SYS_CHIP_GT115_EINT 0x0004
+#define WM8350_SYS_CHIP_GT140_EINT 0x0002
+#define WM8350_SYS_WDOG_TO_EINT 0x0001
+
+/*
+ * R27 (0x1B) - Power Up Interrupt Status
+ */
+#define WM8350_PUTO_LDO4_EINT 0x0800
+#define WM8350_PUTO_LDO3_EINT 0x0400
+#define WM8350_PUTO_LDO2_EINT 0x0200
+#define WM8350_PUTO_LDO1_EINT 0x0100
+#define WM8350_PUTO_DC6_EINT 0x0020
+#define WM8350_PUTO_DC5_EINT 0x0010
+#define WM8350_PUTO_DC4_EINT 0x0008
+#define WM8350_PUTO_DC3_EINT 0x0004
+#define WM8350_PUTO_DC2_EINT 0x0002
+#define WM8350_PUTO_DC1_EINT 0x0001
+
+/*
+ * R28 (0x1C) - Under Voltage Interrupt status
+ */
+#define WM8350_UV_LDO4_EINT 0x0800
+#define WM8350_UV_LDO3_EINT 0x0400
+#define WM8350_UV_LDO2_EINT 0x0200
+#define WM8350_UV_LDO1_EINT 0x0100
+#define WM8350_UV_DC6_EINT 0x0020
+#define WM8350_UV_DC5_EINT 0x0010
+#define WM8350_UV_DC4_EINT 0x0008
+#define WM8350_UV_DC3_EINT 0x0004
+#define WM8350_UV_DC2_EINT 0x0002
+#define WM8350_UV_DC1_EINT 0x0001
+
+/*
+ * R29 (0x1D) - Over Current Interrupt status
+ */
+#define WM8350_OC_LS_EINT 0x8000
+
+/*
+ * R30 (0x1E) - GPIO Interrupt Status
+ */
+#define WM8350_GP12_EINT 0x1000
+#define WM8350_GP11_EINT 0x0800
+#define WM8350_GP10_EINT 0x0400
+#define WM8350_GP9_EINT 0x0200
+#define WM8350_GP8_EINT 0x0100
+#define WM8350_GP7_EINT 0x0080
+#define WM8350_GP6_EINT 0x0040
+#define WM8350_GP5_EINT 0x0020
+#define WM8350_GP4_EINT 0x0010
+#define WM8350_GP3_EINT 0x0008
+#define WM8350_GP2_EINT 0x0004
+#define WM8350_GP1_EINT 0x0002
+#define WM8350_GP0_EINT 0x0001
+
+/*
+ * R31 (0x1F) - Comparator Interrupt Status
+ */
+#define WM8350_EXT_USB_FB_EINT 0x8000
+#define WM8350_EXT_WALL_FB_EINT 0x4000
+#define WM8350_EXT_BAT_FB_EINT 0x2000
+#define WM8350_CODEC_JCK_DET_L_EINT 0x0800
+#define WM8350_CODEC_JCK_DET_R_EINT 0x0400
+#define WM8350_CODEC_MICSCD_EINT 0x0200
+#define WM8350_CODEC_MICD_EINT 0x0100
+#define WM8350_WKUP_OFF_STATE_EINT 0x0040
+#define WM8350_WKUP_HIB_STATE_EINT 0x0020
+#define WM8350_WKUP_CONV_FAULT_EINT 0x0010
+#define WM8350_WKUP_WDOG_RST_EINT 0x0008
+#define WM8350_WKUP_GP_PWR_ON_EINT 0x0004
+#define WM8350_WKUP_ONKEY_EINT 0x0002
+#define WM8350_WKUP_GP_WAKEUP_EINT 0x0001
+
+/*
+ * R32 (0x20) - System Interrupts Mask
+ */
+#define WM8350_IM_OC_INT 0x2000
+#define WM8350_IM_UV_INT 0x1000
+#define WM8350_IM_PUTO_INT 0x0800
+#define WM8350_IM_SPARE_INT 0x0400
+#define WM8350_IM_CS_INT 0x0200
+#define WM8350_IM_EXT_INT 0x0100
+#define WM8350_IM_CODEC_INT 0x0080
+#define WM8350_IM_GP_INT 0x0040
+#define WM8350_IM_AUXADC_INT 0x0020
+#define WM8350_IM_RTC_INT 0x0010
+#define WM8350_IM_SYS_INT 0x0008
+#define WM8350_IM_CHG_INT 0x0004
+#define WM8350_IM_USB_INT 0x0002
+#define WM8350_IM_WKUP_INT 0x0001
+
+/*
+ * R33 (0x21) - Interrupt Status 1 Mask
+ */
+#define WM8350_IM_CHG_BAT_HOT_EINT 0x8000
+#define WM8350_IM_CHG_BAT_COLD_EINT 0x4000
+#define WM8350_IM_CHG_BAT_FAIL_EINT 0x2000
+#define WM8350_IM_CHG_TO_EINT 0x1000
+#define WM8350_IM_CHG_END_EINT 0x0800
+#define WM8350_IM_CHG_START_EINT 0x0400
+#define WM8350_IM_CHG_FAST_RDY_EINT 0x0200
+#define WM8350_IM_RTC_PER_EINT 0x0080
+#define WM8350_IM_RTC_SEC_EINT 0x0040
+#define WM8350_IM_RTC_ALM_EINT 0x0020
+#define WM8350_IM_CHG_VBATT_LT_3P9_EINT 0x0004
+#define WM8350_IM_CHG_VBATT_LT_3P1_EINT 0x0002
+#define WM8350_IM_CHG_VBATT_LT_2P85_EINT 0x0001
+
+/*
+ * R34 (0x22) - Interrupt Status 2 Mask
+ */
+#define WM8350_IM_SPARE2_EINT 0x8000
+#define WM8350_IM_SPARE1_EINT 0x4000
+#define WM8350_IM_CS1_EINT 0x2000
+#define WM8350_IM_CS2_EINT 0x1000
+#define WM8350_IM_USB_LIMIT_EINT 0x0400
+#define WM8350_IM_AUXADC_DATARDY_EINT 0x0100
+#define WM8350_IM_AUXADC_DCOMP4_EINT 0x0080
+#define WM8350_IM_AUXADC_DCOMP3_EINT 0x0040
+#define WM8350_IM_AUXADC_DCOMP2_EINT 0x0020
+#define WM8350_IM_AUXADC_DCOMP1_EINT 0x0010
+#define WM8350_IM_SYS_HYST_COMP_FAIL_EINT 0x0008
+#define WM8350_IM_SYS_CHIP_GT115_EINT 0x0004
+#define WM8350_IM_SYS_CHIP_GT140_EINT 0x0002
+#define WM8350_IM_SYS_WDOG_TO_EINT 0x0001
+
+/*
+ * R35 (0x23) - Power Up Interrupt Status Mask
+ */
+#define WM8350_IM_PUTO_LDO4_EINT 0x0800
+#define WM8350_IM_PUTO_LDO3_EINT 0x0400
+#define WM8350_IM_PUTO_LDO2_EINT 0x0200
+#define WM8350_IM_PUTO_LDO1_EINT 0x0100
+#define WM8350_IM_PUTO_DC6_EINT 0x0020
+#define WM8350_IM_PUTO_DC5_EINT 0x0010
+#define WM8350_IM_PUTO_DC4_EINT 0x0008
+#define WM8350_IM_PUTO_DC3_EINT 0x0004
+#define WM8350_IM_PUTO_DC2_EINT 0x0002
+#define WM8350_IM_PUTO_DC1_EINT 0x0001
+
+/*
+ * R36 (0x24) - Under Voltage Interrupt status Mask
+ */
+#define WM8350_IM_UV_LDO4_EINT 0x0800
+#define WM8350_IM_UV_LDO3_EINT 0x0400
+#define WM8350_IM_UV_LDO2_EINT 0x0200
+#define WM8350_IM_UV_LDO1_EINT 0x0100
+#define WM8350_IM_UV_DC6_EINT 0x0020
+#define WM8350_IM_UV_DC5_EINT 0x0010
+#define WM8350_IM_UV_DC4_EINT 0x0008
+#define WM8350_IM_UV_DC3_EINT 0x0004
+#define WM8350_IM_UV_DC2_EINT 0x0002
+#define WM8350_IM_UV_DC1_EINT 0x0001
+
+/*
+ * R37 (0x25) - Over Current Interrupt status Mask
+ */
+#define WM8350_IM_OC_LS_EINT 0x8000
+
+/*
+ * R38 (0x26) - GPIO Interrupt Status Mask
+ */
+#define WM8350_IM_GP12_EINT 0x1000
+#define WM8350_IM_GP11_EINT 0x0800
+#define WM8350_IM_GP10_EINT 0x0400
+#define WM8350_IM_GP9_EINT 0x0200
+#define WM8350_IM_GP8_EINT 0x0100
+#define WM8350_IM_GP7_EINT 0x0080
+#define WM8350_IM_GP6_EINT 0x0040
+#define WM8350_IM_GP5_EINT 0x0020
+#define WM8350_IM_GP4_EINT 0x0010
+#define WM8350_IM_GP3_EINT 0x0008
+#define WM8350_IM_GP2_EINT 0x0004
+#define WM8350_IM_GP1_EINT 0x0002
+#define WM8350_IM_GP0_EINT 0x0001
+
+/*
+ * R39 (0x27) - Comparator Interrupt Status Mask
+ */
+#define WM8350_IM_EXT_USB_FB_EINT 0x8000
+#define WM8350_IM_EXT_WALL_FB_EINT 0x4000
+#define WM8350_IM_EXT_BAT_FB_EINT 0x2000
+#define WM8350_IM_CODEC_JCK_DET_L_EINT 0x0800
+#define WM8350_IM_CODEC_JCK_DET_R_EINT 0x0400
+#define WM8350_IM_CODEC_MICSCD_EINT 0x0200
+#define WM8350_IM_CODEC_MICD_EINT 0x0100
+#define WM8350_IM_WKUP_OFF_STATE_EINT 0x0040
+#define WM8350_IM_WKUP_HIB_STATE_EINT 0x0020
+#define WM8350_IM_WKUP_CONV_FAULT_EINT 0x0010
+#define WM8350_IM_WKUP_WDOG_RST_EINT 0x0008
+#define WM8350_IM_WKUP_GP_PWR_ON_EINT 0x0004
+#define WM8350_IM_WKUP_ONKEY_EINT 0x0002
+#define WM8350_IM_WKUP_GP_WAKEUP_EINT 0x0001
+
+/*
+ * R220 (0xDC) - RAM BIST 1
+ */
+#define WM8350_READ_STATUS 0x0800
+#define WM8350_TSTRAM_CLK 0x0100
+#define WM8350_TSTRAM_CLK_ENA 0x0080
+#define WM8350_STARTSEQ 0x0040
+#define WM8350_READ_SRC 0x0020
+#define WM8350_COUNT_DIR 0x0010
+#define WM8350_TSTRAM_MODE_MASK 0x000E
+#define WM8350_TSTRAM_ENA 0x0001
+
+/*
+ * R225 (0xE1) - DCDC/LDO status
+ */
+#define WM8350_LS_STS 0x8000
+#define WM8350_LDO4_STS 0x0800
+#define WM8350_LDO3_STS 0x0400
+#define WM8350_LDO2_STS 0x0200
+#define WM8350_LDO1_STS 0x0100
+#define WM8350_DC6_STS 0x0020
+#define WM8350_DC5_STS 0x0010
+#define WM8350_DC4_STS 0x0008
+#define WM8350_DC3_STS 0x0004
+#define WM8350_DC2_STS 0x0002
+#define WM8350_DC1_STS 0x0001
+
+/* WM8350 wake up conditions */
+#define WM8350_IRQ_WKUP_OFF_STATE 43
+#define WM8350_IRQ_WKUP_HIB_STATE 44
+#define WM8350_IRQ_WKUP_CONV_FAULT 45
+#define WM8350_IRQ_WKUP_WDOG_RST 46
+#define WM8350_IRQ_WKUP_GP_PWR_ON 47
+#define WM8350_IRQ_WKUP_ONKEY 48
+#define WM8350_IRQ_WKUP_GP_WAKEUP 49
+
+/* wm8350 chip revisions */
+#define WM8350_REV_E 0x4
+#define WM8350_REV_F 0x5
+#define WM8350_REV_G 0x6
+
+#define WM8350_NUM_IRQ 63
+
+struct wm8350_reg_access {
+ u16 readable; /* Mask of readable bits */
+ u16 writable; /* Mask of writable bits */
+ u16 vol; /* Mask of volatile bits */
+};
+extern const struct wm8350_reg_access wm8350_reg_io_map[];
+extern const u16 wm8350_mode0_defaults[];
+extern const u16 wm8350_mode1_defaults[];
+extern const u16 wm8350_mode2_defaults[];
+extern const u16 wm8350_mode3_defaults[];
+
+struct wm8350;
+
+struct wm8350_irq {
+ void (*handler) (struct wm8350 *, int, void *);
+ void *data;
+};
+
+struct wm8350 {
+ int rev; /* chip revision */
+
+ struct device *dev;
+
+ /* device IO */
+ union {
+ struct i2c_client *i2c_client;
+ struct spi_device *spi_device;
+ };
+ int (*read_dev)(struct wm8350 *wm8350, char reg, int size, void *dest);
+ int (*write_dev)(struct wm8350 *wm8350, char reg, int size,
+ void *src);
+ u16 *reg_cache;
+
+ /* Interrupt handling */
+ struct work_struct irq_work;
+ struct mutex irq_mutex; /* IRQ table mutex */
+ struct wm8350_irq irq[WM8350_NUM_IRQ];
+ int chip_irq;
+
+ /* Client devices */
+ struct wm8350_codec codec;
+ struct wm8350_gpio gpio;
+ struct wm8350_pmic pmic;
+ struct wm8350_power power;
+ struct wm8350_rtc rtc;
+ struct wm8350_wdt wdt;
+};
+
+/**
+ * Data to be supplied by the platform to initialise the WM8350.
+ *
+ * @init: Function called during driver initialisation. Should be
+ * used by the platform to configure GPIO functions and similar.
+ */
+struct wm8350_platform_data {
+ int (*init)(struct wm8350 *wm8350);
+};
+
+
+/*
+ * WM8350 device initialisation and exit.
+ */
+int wm8350_device_init(struct wm8350 *wm8350, int irq,
+ struct wm8350_platform_data *pdata);
+void wm8350_device_exit(struct wm8350 *wm8350);
+
+/*
+ * WM8350 device IO
+ */
+int wm8350_clear_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+int wm8350_set_bits(struct wm8350 *wm8350, u16 reg, u16 mask);
+u16 wm8350_reg_read(struct wm8350 *wm8350, int reg);
+int wm8350_reg_write(struct wm8350 *wm8350, int reg, u16 val);
+int wm8350_reg_lock(struct wm8350 *wm8350);
+int wm8350_reg_unlock(struct wm8350 *wm8350);
+int wm8350_block_read(struct wm8350 *wm8350, int reg, int size, u16 *dest);
+int wm8350_block_write(struct wm8350 *wm8350, int reg, int size, u16 *src);
+
+/*
+ * WM8350 internal interrupts
+ */
+int wm8350_register_irq(struct wm8350 *wm8350, int irq,
+ void (*handler) (struct wm8350 *, int, void *),
+ void *data);
+int wm8350_free_irq(struct wm8350 *wm8350, int irq);
+int wm8350_mask_irq(struct wm8350 *wm8350, int irq);
+int wm8350_unmask_irq(struct wm8350 *wm8350, int irq);
+
+
+#endif
diff --git a/include/linux/mfd/wm8350/gpio.h b/include/linux/mfd/wm8350/gpio.h
new file mode 100644
index 00000000000..ed91e8f5d29
--- /dev/null
+++ b/include/linux/mfd/wm8350/gpio.h
@@ -0,0 +1,342 @@
+/*
+ * gpio.h -- GPIO Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_GPIO_H_
+#define __LINUX_MFD_WM8350_GPIO_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * GPIO Registers.
+ */
+#define WM8350_GPIO_DEBOUNCE 0x80
+#define WM8350_GPIO_PIN_PULL_UP_CONTROL 0x81
+#define WM8350_GPIO_PULL_DOWN_CONTROL 0x82
+#define WM8350_GPIO_INT_MODE 0x83
+#define WM8350_GPIO_CONTROL 0x85
+#define WM8350_GPIO_CONFIGURATION_I_O 0x86
+#define WM8350_GPIO_PIN_POLARITY_TYPE 0x87
+#define WM8350_GPIO_FUNCTION_SELECT_1 0x8C
+#define WM8350_GPIO_FUNCTION_SELECT_2 0x8D
+#define WM8350_GPIO_FUNCTION_SELECT_3 0x8E
+#define WM8350_GPIO_FUNCTION_SELECT_4 0x8F
+
+/*
+ * GPIO Functions
+ */
+#define WM8350_GPIO0_GPIO_IN 0x0
+#define WM8350_GPIO0_GPIO_OUT 0x0
+#define WM8350_GPIO0_PWR_ON_IN 0x1
+#define WM8350_GPIO0_PWR_ON_OUT 0x1
+#define WM8350_GPIO0_LDO_EN_IN 0x2
+#define WM8350_GPIO0_VRTC_OUT 0x2
+#define WM8350_GPIO0_LPWR1_IN 0x3
+#define WM8350_GPIO0_POR_B_OUT 0x3
+
+#define WM8350_GPIO1_GPIO_IN 0x0
+#define WM8350_GPIO1_GPIO_OUT 0x0
+#define WM8350_GPIO1_PWR_ON_IN 0x1
+#define WM8350_GPIO1_DO_CONF_OUT 0x1
+#define WM8350_GPIO1_LDO_EN_IN 0x2
+#define WM8350_GPIO1_RESET_OUT 0x2
+#define WM8350_GPIO1_LPWR2_IN 0x3
+#define WM8350_GPIO1_MEMRST_OUT 0x3
+
+#define WM8350_GPIO2_GPIO_IN 0x0
+#define WM8350_GPIO2_GPIO_OUT 0x0
+#define WM8350_GPIO2_PWR_ON_IN 0x1
+#define WM8350_GPIO2_PWR_ON_OUT 0x1
+#define WM8350_GPIO2_WAKE_UP_IN 0x2
+#define WM8350_GPIO2_VRTC_OUT 0x2
+#define WM8350_GPIO2_32KHZ_IN 0x3
+#define WM8350_GPIO2_32KHZ_OUT 0x3
+
+#define WM8350_GPIO3_GPIO_IN 0x0
+#define WM8350_GPIO3_GPIO_OUT 0x0
+#define WM8350_GPIO3_PWR_ON_IN 0x1
+#define WM8350_GPIO3_P_CLK_OUT 0x1
+#define WM8350_GPIO3_LDO_EN_IN 0x2
+#define WM8350_GPIO3_VRTC_OUT 0x2
+#define WM8350_GPIO3_PWR_OFF_IN 0x3
+#define WM8350_GPIO3_32KHZ_OUT 0x3
+
+#define WM8350_GPIO4_GPIO_IN 0x0
+#define WM8350_GPIO4_GPIO_OUT 0x0
+#define WM8350_GPIO4_MR_IN 0x1
+#define WM8350_GPIO4_MEM_RST_OUT 0x1
+#define WM8350_GPIO4_FLASH_IN 0x2
+#define WM8350_GPIO4_ADA_OUT 0x2
+#define WM8350_GPIO4_HIBERNATE_IN 0x3
+#define WM8350_GPIO4_FLASH_OUT 0x3
+#define WM8350_GPIO4_MICDET_OUT 0x4
+#define WM8350_GPIO4_MICSHT_OUT 0x5
+
+#define WM8350_GPIO5_GPIO_IN 0x0
+#define WM8350_GPIO5_GPIO_OUT 0x0
+#define WM8350_GPIO5_LPWR1_IN 0x1
+#define WM8350_GPIO5_P_CLK_OUT 0x1
+#define WM8350_GPIO5_ADCLRCLK_IN 0x2
+#define WM8350_GPIO5_ADCLRCLK_OUT 0x2
+#define WM8350_GPIO5_HIBERNATE_IN 0x3
+#define WM8350_GPIO5_32KHZ_OUT 0x3
+#define WM8350_GPIO5_MICDET_OUT 0x4
+#define WM8350_GPIO5_MICSHT_OUT 0x5
+#define WM8350_GPIO5_ADA_OUT 0x6
+#define WM8350_GPIO5_OPCLK_OUT 0x7
+
+#define WM8350_GPIO6_GPIO_IN 0x0
+#define WM8350_GPIO6_GPIO_OUT 0x0
+#define WM8350_GPIO6_LPWR2_IN 0x1
+#define WM8350_GPIO6_MEMRST_OUT 0x1
+#define WM8350_GPIO6_FLASH_IN 0x2
+#define WM8350_GPIO6_ADA_OUT 0x2
+#define WM8350_GPIO6_HIBERNATE_IN 0x3
+#define WM8350_GPIO6_RTC_OUT 0x3
+#define WM8350_GPIO6_MICDET_OUT 0x4
+#define WM8350_GPIO6_MICSHT_OUT 0x5
+#define WM8350_GPIO6_ADCLRCLKB_OUT 0x6
+#define WM8350_GPIO6_SDOUT_OUT 0x7
+
+#define WM8350_GPIO7_GPIO_IN 0x0
+#define WM8350_GPIO7_GPIO_OUT 0x0
+#define WM8350_GPIO7_LPWR3_IN 0x1
+#define WM8350_GPIO7_P_CLK_OUT 0x1
+#define WM8350_GPIO7_MASK_IN 0x2
+#define WM8350_GPIO7_VCC_FAULT_OUT 0x2
+#define WM8350_GPIO7_HIBERNATE_IN 0x3
+#define WM8350_GPIO7_BATT_FAULT_OUT 0x3
+#define WM8350_GPIO7_MICDET_OUT 0x4
+#define WM8350_GPIO7_MICSHT_OUT 0x5
+#define WM8350_GPIO7_ADA_OUT 0x6
+#define WM8350_GPIO7_CSB_IN 0x7
+
+#define WM8350_GPIO8_GPIO_IN 0x0
+#define WM8350_GPIO8_GPIO_OUT 0x0
+#define WM8350_GPIO8_MR_IN 0x1
+#define WM8350_GPIO8_VCC_FAULT_OUT 0x1
+#define WM8350_GPIO8_ADCBCLK_IN 0x2
+#define WM8350_GPIO8_ADCBCLK_OUT 0x2
+#define WM8350_GPIO8_PWR_OFF_IN 0x3
+#define WM8350_GPIO8_BATT_FAULT_OUT 0x3
+#define WM8350_GPIO8_ALTSCL_IN 0xf
+
+#define WM8350_GPIO9_GPIO_IN 0x0
+#define WM8350_GPIO9_GPIO_OUT 0x0
+#define WM8350_GPIO9_HEARTBEAT_IN 0x1
+#define WM8350_GPIO9_VCC_FAULT_OUT 0x1
+#define WM8350_GPIO9_MASK_IN 0x2
+#define WM8350_GPIO9_LINE_GT_BATT_OUT 0x2
+#define WM8350_GPIO9_PWR_OFF_IN 0x3
+#define WM8350_GPIO9_BATT_FAULT_OUT 0x3
+#define WM8350_GPIO9_ALTSDA_OUT 0xf
+
+#define WM8350_GPIO10_GPIO_IN 0x0
+#define WM8350_GPIO10_GPIO_OUT 0x0
+#define WM8350_GPIO10_ISINKC_OUT 0x1
+#define WM8350_GPIO10_PWR_OFF_IN 0x2
+#define WM8350_GPIO10_LINE_GT_BATT_OUT 0x2
+#define WM8350_GPIO10_CHD_IND_IN 0x3
+
+#define WM8350_GPIO11_GPIO_IN 0x0
+#define WM8350_GPIO11_GPIO_OUT 0x0
+#define WM8350_GPIO11_ISINKD_OUT 0x1
+#define WM8350_GPIO11_WAKEUP_IN 0x2
+#define WM8350_GPIO11_LINE_GT_BATT_OUT 0x2
+#define WM8350_GPIO11_CHD_IND_IN 0x3
+
+#define WM8350_GPIO12_GPIO_IN 0x0
+#define WM8350_GPIO12_GPIO_OUT 0x0
+#define WM8350_GPIO12_ISINKE_OUT 0x1
+#define WM8350_GPIO12_LINE_GT_BATT_OUT 0x2
+#define WM8350_GPIO12_LINE_EN_OUT 0x3
+#define WM8350_GPIO12_32KHZ_OUT 0x4
+
+#define WM8350_GPIO_DIR_IN 0
+#define WM8350_GPIO_DIR_OUT 1
+#define WM8350_GPIO_ACTIVE_LOW 0
+#define WM8350_GPIO_ACTIVE_HIGH 1
+#define WM8350_GPIO_PULL_NONE 0
+#define WM8350_GPIO_PULL_UP 1
+#define WM8350_GPIO_PULL_DOWN 2
+#define WM8350_GPIO_INVERT_OFF 0
+#define WM8350_GPIO_INVERT_ON 1
+#define WM8350_GPIO_DEBOUNCE_OFF 0
+#define WM8350_GPIO_DEBOUNCE_ON 1
+
+/*
+ * R128 (0x80) - GPIO Debounce
+ */
+#define WM8350_GP12_DB 0x1000
+#define WM8350_GP11_DB 0x0800
+#define WM8350_GP10_DB 0x0400
+#define WM8350_GP9_DB 0x0200
+#define WM8350_GP8_DB 0x0100
+#define WM8350_GP7_DB 0x0080
+#define WM8350_GP6_DB 0x0040
+#define WM8350_GP5_DB 0x0020
+#define WM8350_GP4_DB 0x0010
+#define WM8350_GP3_DB 0x0008
+#define WM8350_GP2_DB 0x0004
+#define WM8350_GP1_DB 0x0002
+#define WM8350_GP0_DB 0x0001
+
+/*
+ * R129 (0x81) - GPIO Pin pull up Control
+ */
+#define WM8350_GP12_PU 0x1000
+#define WM8350_GP11_PU 0x0800
+#define WM8350_GP10_PU 0x0400
+#define WM8350_GP9_PU 0x0200
+#define WM8350_GP8_PU 0x0100
+#define WM8350_GP7_PU 0x0080
+#define WM8350_GP6_PU 0x0040
+#define WM8350_GP5_PU 0x0020
+#define WM8350_GP4_PU 0x0010
+#define WM8350_GP3_PU 0x0008
+#define WM8350_GP2_PU 0x0004
+#define WM8350_GP1_PU 0x0002
+#define WM8350_GP0_PU 0x0001
+
+/*
+ * R130 (0x82) - GPIO Pull down Control
+ */
+#define WM8350_GP12_PD 0x1000
+#define WM8350_GP11_PD 0x0800
+#define WM8350_GP10_PD 0x0400
+#define WM8350_GP9_PD 0x0200
+#define WM8350_GP8_PD 0x0100
+#define WM8350_GP7_PD 0x0080
+#define WM8350_GP6_PD 0x0040
+#define WM8350_GP5_PD 0x0020
+#define WM8350_GP4_PD 0x0010
+#define WM8350_GP3_PD 0x0008
+#define WM8350_GP2_PD 0x0004
+#define WM8350_GP1_PD 0x0002
+#define WM8350_GP0_PD 0x0001
+
+/*
+ * R131 (0x83) - GPIO Interrupt Mode
+ */
+#define WM8350_GP12_INTMODE 0x1000
+#define WM8350_GP11_INTMODE 0x0800
+#define WM8350_GP10_INTMODE 0x0400
+#define WM8350_GP9_INTMODE 0x0200
+#define WM8350_GP8_INTMODE 0x0100
+#define WM8350_GP7_INTMODE 0x0080
+#define WM8350_GP6_INTMODE 0x0040
+#define WM8350_GP5_INTMODE 0x0020
+#define WM8350_GP4_INTMODE 0x0010
+#define WM8350_GP3_INTMODE 0x0008
+#define WM8350_GP2_INTMODE 0x0004
+#define WM8350_GP1_INTMODE 0x0002
+#define WM8350_GP0_INTMODE 0x0001
+
+/*
+ * R133 (0x85) - GPIO Control
+ */
+#define WM8350_GP_DBTIME_MASK 0x00C0
+
+/*
+ * R134 (0x86) - GPIO Configuration (i/o)
+ */
+#define WM8350_GP12_DIR 0x1000
+#define WM8350_GP11_DIR 0x0800
+#define WM8350_GP10_DIR 0x0400
+#define WM8350_GP9_DIR 0x0200
+#define WM8350_GP8_DIR 0x0100
+#define WM8350_GP7_DIR 0x0080
+#define WM8350_GP6_DIR 0x0040
+#define WM8350_GP5_DIR 0x0020
+#define WM8350_GP4_DIR 0x0010
+#define WM8350_GP3_DIR 0x0008
+#define WM8350_GP2_DIR 0x0004
+#define WM8350_GP1_DIR 0x0002
+#define WM8350_GP0_DIR 0x0001
+
+/*
+ * R135 (0x87) - GPIO Pin Polarity / Type
+ */
+#define WM8350_GP12_CFG 0x1000
+#define WM8350_GP11_CFG 0x0800
+#define WM8350_GP10_CFG 0x0400
+#define WM8350_GP9_CFG 0x0200
+#define WM8350_GP8_CFG 0x0100
+#define WM8350_GP7_CFG 0x0080
+#define WM8350_GP6_CFG 0x0040
+#define WM8350_GP5_CFG 0x0020
+#define WM8350_GP4_CFG 0x0010
+#define WM8350_GP3_CFG 0x0008
+#define WM8350_GP2_CFG 0x0004
+#define WM8350_GP1_CFG 0x0002
+#define WM8350_GP0_CFG 0x0001
+
+/*
+ * R140 (0x8C) - GPIO Function Select 1
+ */
+#define WM8350_GP3_FN_MASK 0xF000
+#define WM8350_GP2_FN_MASK 0x0F00
+#define WM8350_GP1_FN_MASK 0x00F0
+#define WM8350_GP0_FN_MASK 0x000F
+
+/*
+ * R141 (0x8D) - GPIO Function Select 2
+ */
+#define WM8350_GP7_FN_MASK 0xF000
+#define WM8350_GP6_FN_MASK 0x0F00
+#define WM8350_GP5_FN_MASK 0x00F0
+#define WM8350_GP4_FN_MASK 0x000F
+
+/*
+ * R142 (0x8E) - GPIO Function Select 3
+ */
+#define WM8350_GP11_FN_MASK 0xF000
+#define WM8350_GP10_FN_MASK 0x0F00
+#define WM8350_GP9_FN_MASK 0x00F0
+#define WM8350_GP8_FN_MASK 0x000F
+
+/*
+ * R143 (0x8F) - GPIO Function Select 4
+ */
+#define WM8350_GP12_FN_MASK 0x000F
+
+/*
+ * R230 (0xE6) - GPIO Pin Status
+ */
+#define WM8350_GP12_LVL 0x1000
+#define WM8350_GP11_LVL 0x0800
+#define WM8350_GP10_LVL 0x0400
+#define WM8350_GP9_LVL 0x0200
+#define WM8350_GP8_LVL 0x0100
+#define WM8350_GP7_LVL 0x0080
+#define WM8350_GP6_LVL 0x0040
+#define WM8350_GP5_LVL 0x0020
+#define WM8350_GP4_LVL 0x0010
+#define WM8350_GP3_LVL 0x0008
+#define WM8350_GP2_LVL 0x0004
+#define WM8350_GP1_LVL 0x0002
+#define WM8350_GP0_LVL 0x0001
+
+struct wm8350;
+
+int wm8350_gpio_config(struct wm8350 *wm8350, int gpio, int dir, int func,
+ int pol, int pull, int invert, int debounce);
+
+struct wm8350_gpio {
+ struct platform_device *pdev;
+};
+
+/*
+ * GPIO Interrupts
+ */
+#define WM8350_IRQ_GPIO(x) (50 + x)
+
+#endif
diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h
new file mode 100644
index 00000000000..69b69e07f62
--- /dev/null
+++ b/include/linux/mfd/wm8350/pmic.h
@@ -0,0 +1,741 @@
+/*
+ * pmic.h -- Power Managment Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_PMIC_H
+#define __LINUX_MFD_WM8350_PMIC_H
+
+/*
+ * Register values.
+ */
+
+#define WM8350_CURRENT_SINK_DRIVER_A 0xAC
+#define WM8350_CSA_FLASH_CONTROL 0xAD
+#define WM8350_CURRENT_SINK_DRIVER_B 0xAE
+#define WM8350_CSB_FLASH_CONTROL 0xAF
+#define WM8350_DCDC_LDO_REQUESTED 0xB0
+#define WM8350_DCDC_ACTIVE_OPTIONS 0xB1
+#define WM8350_DCDC_SLEEP_OPTIONS 0xB2
+#define WM8350_POWER_CHECK_COMPARATOR 0xB3
+#define WM8350_DCDC1_CONTROL 0xB4
+#define WM8350_DCDC1_TIMEOUTS 0xB5
+#define WM8350_DCDC1_LOW_POWER 0xB6
+#define WM8350_DCDC2_CONTROL 0xB7
+#define WM8350_DCDC2_TIMEOUTS 0xB8
+#define WM8350_DCDC3_CONTROL 0xBA
+#define WM8350_DCDC3_TIMEOUTS 0xBB
+#define WM8350_DCDC3_LOW_POWER 0xBC
+#define WM8350_DCDC4_CONTROL 0xBD
+#define WM8350_DCDC4_TIMEOUTS 0xBE
+#define WM8350_DCDC4_LOW_POWER 0xBF
+#define WM8350_DCDC5_CONTROL 0xC0
+#define WM8350_DCDC5_TIMEOUTS 0xC1
+#define WM8350_DCDC6_CONTROL 0xC3
+#define WM8350_DCDC6_TIMEOUTS 0xC4
+#define WM8350_DCDC6_LOW_POWER 0xC5
+#define WM8350_LIMIT_SWITCH_CONTROL 0xC7
+#define WM8350_LDO1_CONTROL 0xC8
+#define WM8350_LDO1_TIMEOUTS 0xC9
+#define WM8350_LDO1_LOW_POWER 0xCA
+#define WM8350_LDO2_CONTROL 0xCB
+#define WM8350_LDO2_TIMEOUTS 0xCC
+#define WM8350_LDO2_LOW_POWER 0xCD
+#define WM8350_LDO3_CONTROL 0xCE
+#define WM8350_LDO3_TIMEOUTS 0xCF
+#define WM8350_LDO3_LOW_POWER 0xD0
+#define WM8350_LDO4_CONTROL 0xD1
+#define WM8350_LDO4_TIMEOUTS 0xD2
+#define WM8350_LDO4_LOW_POWER 0xD3
+#define WM8350_VCC_FAULT_MASKS 0xD7
+#define WM8350_MAIN_BANDGAP_CONTROL 0xD8
+#define WM8350_OSC_CONTROL 0xD9
+#define WM8350_RTC_TICK_CONTROL 0xDA
+#define WM8350_SECURITY 0xDB
+#define WM8350_RAM_BIST_1 0xDC
+#define WM8350_DCDC_LDO_STATUS 0xE1
+#define WM8350_GPIO_PIN_STATUS 0xE6
+
+#define WM8350_DCDC1_FORCE_PWM 0xF8
+#define WM8350_DCDC3_FORCE_PWM 0xFA
+#define WM8350_DCDC4_FORCE_PWM 0xFB
+#define WM8350_DCDC6_FORCE_PWM 0xFD
+
+/*
+ * R172 (0xAC) - Current Sink Driver A
+ */
+#define WM8350_CS1_HIB_MODE 0x1000
+#define WM8350_CS1_HIB_MODE_MASK 0x1000
+#define WM8350_CS1_HIB_MODE_SHIFT 12
+#define WM8350_CS1_ISEL_MASK 0x003F
+#define WM8350_CS1_ISEL_SHIFT 0
+
+/* Bit values for R172 (0xAC) */
+#define WM8350_CS1_HIB_MODE_DISABLE 0
+#define WM8350_CS1_HIB_MODE_LEAVE 1
+
+#define WM8350_CS1_ISEL_220M 0x3F
+
+/*
+ * R173 (0xAD) - CSA Flash control
+ */
+#define WM8350_CS1_FLASH_MODE 0x8000
+#define WM8350_CS1_TRIGSRC 0x4000
+#define WM8350_CS1_DRIVE 0x2000
+#define WM8350_CS1_FLASH_DUR_MASK 0x0300
+#define WM8350_CS1_OFF_RAMP_MASK 0x0030
+#define WM8350_CS1_ON_RAMP_MASK 0x0003
+
+/*
+ * R174 (0xAE) - Current Sink Driver B
+ */
+#define WM8350_CS2_HIB_MODE 0x1000
+#define WM8350_CS2_ISEL_MASK 0x003F
+
+/*
+ * R175 (0xAF) - CSB Flash control
+ */
+#define WM8350_CS2_FLASH_MODE 0x8000
+#define WM8350_CS2_TRIGSRC 0x4000
+#define WM8350_CS2_DRIVE 0x2000
+#define WM8350_CS2_FLASH_DUR_MASK 0x0300
+#define WM8350_CS2_OFF_RAMP_MASK 0x0030
+#define WM8350_CS2_ON_RAMP_MASK 0x0003
+
+/*
+ * R176 (0xB0) - DCDC/LDO requested
+ */
+#define WM8350_LS_ENA 0x8000
+#define WM8350_LDO4_ENA 0x0800
+#define WM8350_LDO3_ENA 0x0400
+#define WM8350_LDO2_ENA 0x0200
+#define WM8350_LDO1_ENA 0x0100
+#define WM8350_DC6_ENA 0x0020
+#define WM8350_DC5_ENA 0x0010
+#define WM8350_DC4_ENA 0x0008
+#define WM8350_DC3_ENA 0x0004
+#define WM8350_DC2_ENA 0x0002
+#define WM8350_DC1_ENA 0x0001
+
+/*
+ * R177 (0xB1) - DCDC Active options
+ */
+#define WM8350_PUTO_MASK 0x3000
+#define WM8350_PWRUP_DELAY_MASK 0x0300
+#define WM8350_DC6_ACTIVE 0x0020
+#define WM8350_DC4_ACTIVE 0x0008
+#define WM8350_DC3_ACTIVE 0x0004
+#define WM8350_DC1_ACTIVE 0x0001
+
+/*
+ * R178 (0xB2) - DCDC Sleep options
+ */
+#define WM8350_DC6_SLEEP 0x0020
+#define WM8350_DC4_SLEEP 0x0008
+#define WM8350_DC3_SLEEP 0x0004
+#define WM8350_DC1_SLEEP 0x0001
+
+/*
+ * R179 (0xB3) - Power-check comparator
+ */
+#define WM8350_PCCMP_ERRACT 0x4000
+#define WM8350_PCCMP_RAIL 0x0100
+#define WM8350_PCCMP_OFF_THR_MASK 0x0070
+#define WM8350_PCCMP_ON_THR_MASK 0x0007
+
+/*
+ * R180 (0xB4) - DCDC1 Control
+ */
+#define WM8350_DC1_OPFLT 0x0400
+#define WM8350_DC1_VSEL_MASK 0x007F
+#define WM8350_DC1_VSEL_SHIFT 0
+
+/*
+ * R181 (0xB5) - DCDC1 Timeouts
+ */
+#define WM8350_DC1_ERRACT_MASK 0xC000
+#define WM8350_DC1_ERRACT_SHIFT 14
+#define WM8350_DC1_ENSLOT_MASK 0x3C00
+#define WM8350_DC1_ENSLOT_SHIFT 10
+#define WM8350_DC1_SDSLOT_MASK 0x03C0
+#define WM8350_DC1_UVTO_MASK 0x0030
+#define WM8350_DC1_SDSLOT_SHIFT 6
+
+/* Bit values for R181 (0xB5) */
+#define WM8350_DC1_ERRACT_NONE 0
+#define WM8350_DC1_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC1_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R182 (0xB6) - DCDC1 Low Power
+ */
+#define WM8350_DC1_HIB_MODE_MASK 0x7000
+#define WM8350_DC1_HIB_TRIG_MASK 0x0300
+#define WM8350_DC1_VIMG_MASK 0x007F
+
+/*
+ * R183 (0xB7) - DCDC2 Control
+ */
+#define WM8350_DC2_MODE 0x4000
+#define WM8350_DC2_MODE_MASK 0x4000
+#define WM8350_DC2_MODE_SHIFT 14
+#define WM8350_DC2_HIB_MODE 0x1000
+#define WM8350_DC2_HIB_MODE_MASK 0x1000
+#define WM8350_DC2_HIB_MODE_SHIFT 12
+#define WM8350_DC2_HIB_TRIG_MASK 0x0300
+#define WM8350_DC2_HIB_TRIG_SHIFT 8
+#define WM8350_DC2_ILIM 0x0040
+#define WM8350_DC2_ILIM_MASK 0x0040
+#define WM8350_DC2_ILIM_SHIFT 6
+#define WM8350_DC2_RMP_MASK 0x0018
+#define WM8350_DC2_RMP_SHIFT 3
+#define WM8350_DC2_FBSRC_MASK 0x0003
+#define WM8350_DC2_FBSRC_SHIFT 0
+
+/* Bit values for R183 (0xB7) */
+#define WM8350_DC2_MODE_BOOST 0
+#define WM8350_DC2_MODE_SWITCH 1
+
+#define WM8350_DC2_HIB_MODE_ACTIVE 1
+#define WM8350_DC2_HIB_MODE_DISABLE 0
+
+#define WM8350_DC2_HIB_TRIG_NONE 0
+#define WM8350_DC2_HIB_TRIG_LPWR1 1
+#define WM8350_DC2_HIB_TRIG_LPWR2 2
+#define WM8350_DC2_HIB_TRIG_LPWR3 3
+
+#define WM8350_DC2_ILIM_HIGH 0
+#define WM8350_DC2_ILIM_LOW 1
+
+#define WM8350_DC2_RMP_30V 0
+#define WM8350_DC2_RMP_20V 1
+#define WM8350_DC2_RMP_10V 2
+#define WM8350_DC2_RMP_5V 3
+
+#define WM8350_DC2_FBSRC_FB2 0
+#define WM8350_DC2_FBSRC_ISINKA 1
+#define WM8350_DC2_FBSRC_ISINKB 2
+#define WM8350_DC2_FBSRC_USB 3
+
+/*
+ * R184 (0xB8) - DCDC2 Timeouts
+ */
+#define WM8350_DC2_ERRACT_MASK 0xC000
+#define WM8350_DC2_ERRACT_SHIFT 14
+#define WM8350_DC2_ENSLOT_MASK 0x3C00
+#define WM8350_DC2_ENSLOT_SHIFT 10
+#define WM8350_DC2_SDSLOT_MASK 0x03C0
+#define WM8350_DC2_UVTO_MASK 0x0030
+
+/* Bit values for R184 (0xB8) */
+#define WM8350_DC2_ERRACT_NONE 0
+#define WM8350_DC2_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC2_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R186 (0xBA) - DCDC3 Control
+ */
+#define WM8350_DC3_OPFLT 0x0400
+#define WM8350_DC3_VSEL_MASK 0x007F
+#define WM8350_DC3_VSEL_SHIFT 0
+
+/*
+ * R187 (0xBB) - DCDC3 Timeouts
+ */
+#define WM8350_DC3_ERRACT_MASK 0xC000
+#define WM8350_DC3_ERRACT_SHIFT 14
+#define WM8350_DC3_ENSLOT_MASK 0x3C00
+#define WM8350_DC3_ENSLOT_SHIFT 10
+#define WM8350_DC3_SDSLOT_MASK 0x03C0
+#define WM8350_DC3_UVTO_MASK 0x0030
+#define WM8350_DC3_SDSLOT_SHIFT 6
+
+/* Bit values for R187 (0xBB) */
+#define WM8350_DC3_ERRACT_NONE 0
+#define WM8350_DC3_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC3_ERRACT_SHUTDOWN_SYS 2
+/*
+ * R188 (0xBC) - DCDC3 Low Power
+ */
+#define WM8350_DC3_HIB_MODE_MASK 0x7000
+#define WM8350_DC3_HIB_TRIG_MASK 0x0300
+#define WM8350_DC3_VIMG_MASK 0x007F
+
+/*
+ * R189 (0xBD) - DCDC4 Control
+ */
+#define WM8350_DC4_OPFLT 0x0400
+#define WM8350_DC4_VSEL_MASK 0x007F
+#define WM8350_DC4_VSEL_SHIFT 0
+
+/*
+ * R190 (0xBE) - DCDC4 Timeouts
+ */
+#define WM8350_DC4_ERRACT_MASK 0xC000
+#define WM8350_DC4_ERRACT_SHIFT 14
+#define WM8350_DC4_ENSLOT_MASK 0x3C00
+#define WM8350_DC4_ENSLOT_SHIFT 10
+#define WM8350_DC4_SDSLOT_MASK 0x03C0
+#define WM8350_DC4_UVTO_MASK 0x0030
+#define WM8350_DC4_SDSLOT_SHIFT 6
+
+/* Bit values for R190 (0xBE) */
+#define WM8350_DC4_ERRACT_NONE 0
+#define WM8350_DC4_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC4_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R191 (0xBF) - DCDC4 Low Power
+ */
+#define WM8350_DC4_HIB_MODE_MASK 0x7000
+#define WM8350_DC4_HIB_TRIG_MASK 0x0300
+#define WM8350_DC4_VIMG_MASK 0x007F
+
+/*
+ * R192 (0xC0) - DCDC5 Control
+ */
+#define WM8350_DC5_MODE 0x4000
+#define WM8350_DC5_MODE_MASK 0x4000
+#define WM8350_DC5_MODE_SHIFT 14
+#define WM8350_DC5_HIB_MODE 0x1000
+#define WM8350_DC5_HIB_MODE_MASK 0x1000
+#define WM8350_DC5_HIB_MODE_SHIFT 12
+#define WM8350_DC5_HIB_TRIG_MASK 0x0300
+#define WM8350_DC5_HIB_TRIG_SHIFT 8
+#define WM8350_DC5_ILIM 0x0040
+#define WM8350_DC5_ILIM_MASK 0x0040
+#define WM8350_DC5_ILIM_SHIFT 6
+#define WM8350_DC5_RMP_MASK 0x0018
+#define WM8350_DC5_RMP_SHIFT 3
+#define WM8350_DC5_FBSRC_MASK 0x0003
+#define WM8350_DC5_FBSRC_SHIFT 0
+
+/* Bit values for R192 (0xC0) */
+#define WM8350_DC5_MODE_BOOST 0
+#define WM8350_DC5_MODE_SWITCH 1
+
+#define WM8350_DC5_HIB_MODE_ACTIVE 1
+#define WM8350_DC5_HIB_MODE_DISABLE 0
+
+#define WM8350_DC5_HIB_TRIG_NONE 0
+#define WM8350_DC5_HIB_TRIG_LPWR1 1
+#define WM8350_DC5_HIB_TRIG_LPWR2 2
+#define WM8350_DC5_HIB_TRIG_LPWR3 3
+
+#define WM8350_DC5_ILIM_HIGH 0
+#define WM8350_DC5_ILIM_LOW 1
+
+#define WM8350_DC5_RMP_30V 0
+#define WM8350_DC5_RMP_20V 1
+#define WM8350_DC5_RMP_10V 2
+#define WM8350_DC5_RMP_5V 3
+
+#define WM8350_DC5_FBSRC_FB2 0
+#define WM8350_DC5_FBSRC_ISINKA 1
+#define WM8350_DC5_FBSRC_ISINKB 2
+#define WM8350_DC5_FBSRC_USB 3
+
+/*
+ * R193 (0xC1) - DCDC5 Timeouts
+ */
+#define WM8350_DC5_ERRACT_MASK 0xC000
+#define WM8350_DC5_ERRACT_SHIFT 14
+#define WM8350_DC5_ENSLOT_MASK 0x3C00
+#define WM8350_DC5_ENSLOT_SHIFT 10
+#define WM8350_DC5_SDSLOT_MASK 0x03C0
+#define WM8350_DC5_UVTO_MASK 0x0030
+#define WM8350_DC5_SDSLOT_SHIFT 6
+
+/* Bit values for R193 (0xC1) */
+#define WM8350_DC5_ERRACT_NONE 0
+#define WM8350_DC5_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC5_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R195 (0xC3) - DCDC6 Control
+ */
+#define WM8350_DC6_OPFLT 0x0400
+#define WM8350_DC6_VSEL_MASK 0x007F
+#define WM8350_DC6_VSEL_SHIFT 0
+
+/*
+ * R196 (0xC4) - DCDC6 Timeouts
+ */
+#define WM8350_DC6_ERRACT_MASK 0xC000
+#define WM8350_DC6_ERRACT_SHIFT 14
+#define WM8350_DC6_ENSLOT_MASK 0x3C00
+#define WM8350_DC6_ENSLOT_SHIFT 10
+#define WM8350_DC6_SDSLOT_MASK 0x03C0
+#define WM8350_DC6_UVTO_MASK 0x0030
+#define WM8350_DC6_SDSLOT_SHIFT 6
+
+/* Bit values for R196 (0xC4) */
+#define WM8350_DC6_ERRACT_NONE 0
+#define WM8350_DC6_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_DC6_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R197 (0xC5) - DCDC6 Low Power
+ */
+#define WM8350_DC6_HIB_MODE_MASK 0x7000
+#define WM8350_DC6_HIB_TRIG_MASK 0x0300
+#define WM8350_DC6_VIMG_MASK 0x007F
+
+/*
+ * R199 (0xC7) - Limit Switch Control
+ */
+#define WM8350_LS_ERRACT_MASK 0xC000
+#define WM8350_LS_ERRACT_SHIFT 14
+#define WM8350_LS_ENSLOT_MASK 0x3C00
+#define WM8350_LS_ENSLOT_SHIFT 10
+#define WM8350_LS_SDSLOT_MASK 0x03C0
+#define WM8350_LS_SDSLOT_SHIFT 6
+#define WM8350_LS_HIB_MODE 0x0010
+#define WM8350_LS_HIB_MODE_MASK 0x0010
+#define WM8350_LS_HIB_MODE_SHIFT 4
+#define WM8350_LS_HIB_PROT 0x0002
+#define WM8350_LS_HIB_PROT_MASK 0x0002
+#define WM8350_LS_HIB_PROT_SHIFT 1
+#define WM8350_LS_PROT 0x0001
+#define WM8350_LS_PROT_MASK 0x0001
+#define WM8350_LS_PROT_SHIFT 0
+
+/* Bit values for R199 (0xC7) */
+#define WM8350_LS_ERRACT_NONE 0
+#define WM8350_LS_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_LS_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R200 (0xC8) - LDO1 Control
+ */
+#define WM8350_LDO1_SWI 0x4000
+#define WM8350_LDO1_OPFLT 0x0400
+#define WM8350_LDO1_VSEL_MASK 0x001F
+#define WM8350_LDO1_VSEL_SHIFT 0
+
+/*
+ * R201 (0xC9) - LDO1 Timeouts
+ */
+#define WM8350_LDO1_ERRACT_MASK 0xC000
+#define WM8350_LDO1_ERRACT_SHIFT 14
+#define WM8350_LDO1_ENSLOT_MASK 0x3C00
+#define WM8350_LDO1_ENSLOT_SHIFT 10
+#define WM8350_LDO1_SDSLOT_MASK 0x03C0
+#define WM8350_LDO1_UVTO_MASK 0x0030
+#define WM8350_LDO1_SDSLOT_SHIFT 6
+
+/* Bit values for R201 (0xC9) */
+#define WM8350_LDO1_ERRACT_NONE 0
+#define WM8350_LDO1_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_LDO1_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R202 (0xCA) - LDO1 Low Power
+ */
+#define WM8350_LDO1_HIB_MODE_MASK 0x3000
+#define WM8350_LDO1_HIB_TRIG_MASK 0x0300
+#define WM8350_LDO1_VIMG_MASK 0x001F
+#define WM8350_LDO1_HIB_MODE_DIS (0x1 << 12)
+
+
+/*
+ * R203 (0xCB) - LDO2 Control
+ */
+#define WM8350_LDO2_SWI 0x4000
+#define WM8350_LDO2_OPFLT 0x0400
+#define WM8350_LDO2_VSEL_MASK 0x001F
+#define WM8350_LDO2_VSEL_SHIFT 0
+
+/*
+ * R204 (0xCC) - LDO2 Timeouts
+ */
+#define WM8350_LDO2_ERRACT_MASK 0xC000
+#define WM8350_LDO2_ERRACT_SHIFT 14
+#define WM8350_LDO2_ENSLOT_MASK 0x3C00
+#define WM8350_LDO2_ENSLOT_SHIFT 10
+#define WM8350_LDO2_SDSLOT_MASK 0x03C0
+#define WM8350_LDO2_SDSLOT_SHIFT 6
+
+/* Bit values for R204 (0xCC) */
+#define WM8350_LDO2_ERRACT_NONE 0
+#define WM8350_LDO2_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_LDO2_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R205 (0xCD) - LDO2 Low Power
+ */
+#define WM8350_LDO2_HIB_MODE_MASK 0x3000
+#define WM8350_LDO2_HIB_TRIG_MASK 0x0300
+#define WM8350_LDO2_VIMG_MASK 0x001F
+
+/*
+ * R206 (0xCE) - LDO3 Control
+ */
+#define WM8350_LDO3_SWI 0x4000
+#define WM8350_LDO3_OPFLT 0x0400
+#define WM8350_LDO3_VSEL_MASK 0x001F
+#define WM8350_LDO3_VSEL_SHIFT 0
+
+/*
+ * R207 (0xCF) - LDO3 Timeouts
+ */
+#define WM8350_LDO3_ERRACT_MASK 0xC000
+#define WM8350_LDO3_ERRACT_SHIFT 14
+#define WM8350_LDO3_ENSLOT_MASK 0x3C00
+#define WM8350_LDO3_ENSLOT_SHIFT 10
+#define WM8350_LDO3_SDSLOT_MASK 0x03C0
+#define WM8350_LDO3_UVTO_MASK 0x0030
+#define WM8350_LDO3_SDSLOT_SHIFT 6
+
+/* Bit values for R207 (0xCF) */
+#define WM8350_LDO3_ERRACT_NONE 0
+#define WM8350_LDO3_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_LDO3_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R208 (0xD0) - LDO3 Low Power
+ */
+#define WM8350_LDO3_HIB_MODE_MASK 0x3000
+#define WM8350_LDO3_HIB_TRIG_MASK 0x0300
+#define WM8350_LDO3_VIMG_MASK 0x001F
+
+/*
+ * R209 (0xD1) - LDO4 Control
+ */
+#define WM8350_LDO4_SWI 0x4000
+#define WM8350_LDO4_OPFLT 0x0400
+#define WM8350_LDO4_VSEL_MASK 0x001F
+#define WM8350_LDO4_VSEL_SHIFT 0
+
+/*
+ * R210 (0xD2) - LDO4 Timeouts
+ */
+#define WM8350_LDO4_ERRACT_MASK 0xC000
+#define WM8350_LDO4_ERRACT_SHIFT 14
+#define WM8350_LDO4_ENSLOT_MASK 0x3C00
+#define WM8350_LDO4_ENSLOT_SHIFT 10
+#define WM8350_LDO4_SDSLOT_MASK 0x03C0
+#define WM8350_LDO4_UVTO_MASK 0x0030
+#define WM8350_LDO4_SDSLOT_SHIFT 6
+
+/* Bit values for R210 (0xD2) */
+#define WM8350_LDO4_ERRACT_NONE 0
+#define WM8350_LDO4_ERRACT_SHUTDOWN_CONV 1
+#define WM8350_LDO4_ERRACT_SHUTDOWN_SYS 2
+
+/*
+ * R211 (0xD3) - LDO4 Low Power
+ */
+#define WM8350_LDO4_HIB_MODE_MASK 0x3000
+#define WM8350_LDO4_HIB_TRIG_MASK 0x0300
+#define WM8350_LDO4_VIMG_MASK 0x001F
+
+/*
+ * R215 (0xD7) - VCC_FAULT Masks
+ */
+#define WM8350_LS_FAULT 0x8000
+#define WM8350_LDO4_FAULT 0x0800
+#define WM8350_LDO3_FAULT 0x0400
+#define WM8350_LDO2_FAULT 0x0200
+#define WM8350_LDO1_FAULT 0x0100
+#define WM8350_DC6_FAULT 0x0020
+#define WM8350_DC5_FAULT 0x0010
+#define WM8350_DC4_FAULT 0x0008
+#define WM8350_DC3_FAULT 0x0004
+#define WM8350_DC2_FAULT 0x0002
+#define WM8350_DC1_FAULT 0x0001
+
+/*
+ * R216 (0xD8) - Main Bandgap Control
+ */
+#define WM8350_MBG_LOAD_FUSES 0x8000
+#define WM8350_MBG_FUSE_WPREP 0x4000
+#define WM8350_MBG_FUSE_WRITE 0x2000
+#define WM8350_MBG_FUSE_TRIM_MASK 0x1F00
+#define WM8350_MBG_TRIM_SRC 0x0020
+#define WM8350_MBG_USER_TRIM_MASK 0x001F
+
+/*
+ * R217 (0xD9) - OSC Control
+ */
+#define WM8350_OSC_LOAD_FUSES 0x8000
+#define WM8350_OSC_FUSE_WPREP 0x4000
+#define WM8350_OSC_FUSE_WRITE 0x2000
+#define WM8350_OSC_FUSE_TRIM_MASK 0x0F00
+#define WM8350_OSC_TRIM_SRC 0x0020
+#define WM8350_OSC_USER_TRIM_MASK 0x000F
+
+/*
+ * R248 (0xF8) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC1_FORCE_PWM_ENA 0x0010
+
+/*
+ * R250 (0xFA) - DCDC3 Force PWM
+ */
+#define WM8350_DCDC3_FORCE_PWM_ENA 0x0010
+
+/*
+ * R251 (0xFB) - DCDC4 Force PWM
+ */
+#define WM8350_DCDC4_FORCE_PWM_ENA 0x0010
+
+/*
+ * R253 (0xFD) - DCDC1 Force PWM
+ */
+#define WM8350_DCDC6_FORCE_PWM_ENA 0x0010
+
+/*
+ * DCDC's
+ */
+#define WM8350_DCDC_1 0
+#define WM8350_DCDC_2 1
+#define WM8350_DCDC_3 2
+#define WM8350_DCDC_4 3
+#define WM8350_DCDC_5 4
+#define WM8350_DCDC_6 5
+
+/* DCDC modes */
+#define WM8350_DCDC_ACTIVE_STANDBY 0
+#define WM8350_DCDC_ACTIVE_PULSE 1
+#define WM8350_DCDC_SLEEP_NORMAL 0
+#define WM8350_DCDC_SLEEP_LOW 1
+
+/* DCDC Low power (Hibernate) mode */
+#define WM8350_DCDC_HIB_MODE_CUR (0 << 12)
+#define WM8350_DCDC_HIB_MODE_IMAGE (1 << 12)
+#define WM8350_DCDC_HIB_MODE_STANDBY (2 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO (4 << 12)
+#define WM8350_DCDC_HIB_MODE_LDO_IM (5 << 12)
+#define WM8350_DCDC_HIB_MODE_DIS (7 << 12)
+#define WM8350_DCDC_HIB_MODE_MASK (7 << 12)
+
+/* DCDC Low Power (Hibernate) signal */
+#define WM8350_DCDC_HIB_SIG_REG (0 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR1 (1 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR2 (2 << 8)
+#define WM8350_DCDC_HIB_SIG_LPWR3 (3 << 8)
+
+/* LDO Low power (Hibernate) mode */
+#define WM8350_LDO_HIB_MODE_IMAGE (0 << 0)
+#define WM8350_LDO_HIB_MODE_DIS (1 << 0)
+
+/* LDO Low Power (Hibernate) signal */
+#define WM8350_LDO_HIB_SIG_REG (0 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR1 (1 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR2 (2 << 8)
+#define WM8350_LDO_HIB_SIG_LPWR3 (3 << 8)
+
+/*
+ * LDOs
+ */
+#define WM8350_LDO_1 6
+#define WM8350_LDO_2 7
+#define WM8350_LDO_3 8
+#define WM8350_LDO_4 9
+
+/*
+ * ISINKs
+ */
+#define WM8350_ISINK_A 10
+#define WM8350_ISINK_B 11
+
+#define WM8350_ISINK_MODE_BOOST 0
+#define WM8350_ISINK_MODE_SWITCH 1
+#define WM8350_ISINK_ILIM_NORMAL 0
+#define WM8350_ISINK_ILIM_LOW 1
+
+#define WM8350_ISINK_FLASH_DISABLE 0
+#define WM8350_ISINK_FLASH_ENABLE 1
+#define WM8350_ISINK_FLASH_TRIG_BIT 0
+#define WM8350_ISINK_FLASH_TRIG_GPIO 1
+#define WM8350_ISINK_FLASH_MODE_EN (1 << 13)
+#define WM8350_ISINK_FLASH_MODE_DIS (0 << 13)
+#define WM8350_ISINK_FLASH_DUR_32MS (0 << 8)
+#define WM8350_ISINK_FLASH_DUR_64MS (1 << 8)
+#define WM8350_ISINK_FLASH_DUR_96MS (2 << 8)
+#define WM8350_ISINK_FLASH_DUR_1024MS (3 << 8)
+#define WM8350_ISINK_FLASH_ON_INSTANT (0 << 4)
+#define WM8350_ISINK_FLASH_ON_0_25S (1 << 4)
+#define WM8350_ISINK_FLASH_ON_0_50S (2 << 4)
+#define WM8350_ISINK_FLASH_ON_1_00S (3 << 4)
+#define WM8350_ISINK_FLASH_ON_1_95S (1 << 4)
+#define WM8350_ISINK_FLASH_ON_3_91S (2 << 4)
+#define WM8350_ISINK_FLASH_ON_7_80S (3 << 4)
+#define WM8350_ISINK_FLASH_OFF_INSTANT (0 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_25S (1 << 0)
+#define WM8350_ISINK_FLASH_OFF_0_50S (2 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_00S (3 << 0)
+#define WM8350_ISINK_FLASH_OFF_1_95S (1 << 0)
+#define WM8350_ISINK_FLASH_OFF_3_91S (2 << 0)
+#define WM8350_ISINK_FLASH_OFF_7_80S (3 << 0)
+
+/*
+ * Regulator Interrupts.
+ */
+#define WM8350_IRQ_CS1 13
+#define WM8350_IRQ_CS2 14
+#define WM8350_IRQ_UV_LDO4 25
+#define WM8350_IRQ_UV_LDO3 26
+#define WM8350_IRQ_UV_LDO2 27
+#define WM8350_IRQ_UV_LDO1 28
+#define WM8350_IRQ_UV_DC6 29
+#define WM8350_IRQ_UV_DC5 30
+#define WM8350_IRQ_UV_DC4 31
+#define WM8350_IRQ_UV_DC3 32
+#define WM8350_IRQ_UV_DC2 33
+#define WM8350_IRQ_UV_DC1 34
+#define WM8350_IRQ_OC_LS 35
+
+#define NUM_WM8350_REGULATORS 12
+
+struct wm8350;
+struct platform_device;
+struct regulator_init_data;
+
+struct wm8350_pmic {
+ /* ISINK to DCDC mapping */
+ int isink_A_dcdc;
+ int isink_B_dcdc;
+
+ /* hibernate configs */
+ u16 dcdc1_hib_mode;
+ u16 dcdc3_hib_mode;
+ u16 dcdc4_hib_mode;
+ u16 dcdc6_hib_mode;
+
+ /* regulator devices */
+ struct platform_device *pdev[NUM_WM8350_REGULATORS];
+};
+
+int wm8350_register_regulator(struct wm8350 *wm8350, int reg,
+ struct regulator_init_data *initdata);
+
+/*
+ * Additional DCDC control not supported via regulator API
+ */
+int wm8350_dcdc_set_slot(struct wm8350 *wm8350, int dcdc, u16 start,
+ u16 stop, u16 fault);
+int wm8350_dcdc25_set_mode(struct wm8350 *wm8350, int dcdc, u16 mode,
+ u16 ilim, u16 ramp, u16 feedback);
+
+/*
+ * Additional LDO control not supported via regulator API
+ */
+int wm8350_ldo_set_slot(struct wm8350 *wm8350, int ldo, u16 start, u16 stop);
+
+/*
+ * Additional ISINK control not supported via regulator API
+ */
+int wm8350_isink_set_flash(struct wm8350 *wm8350, int isink, u16 mode,
+ u16 trigger, u16 duration, u16 on_ramp,
+ u16 off_ramp, u16 drive);
+
+#endif
diff --git a/include/linux/mfd/wm8350/rtc.h b/include/linux/mfd/wm8350/rtc.h
new file mode 100644
index 00000000000..dfda69e9f44
--- /dev/null
+++ b/include/linux/mfd/wm8350/rtc.h
@@ -0,0 +1,266 @@
+/*
+ * rtc.h -- RTC driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_RTC_H
+#define __LINUX_MFD_WM8350_RTC_H
+
+#include <linux/platform_device.h>
+
+/*
+ * Register values.
+ */
+#define WM8350_RTC_SECONDS_MINUTES 0x10
+#define WM8350_RTC_HOURS_DAY 0x11
+#define WM8350_RTC_DATE_MONTH 0x12
+#define WM8350_RTC_YEAR 0x13
+#define WM8350_ALARM_SECONDS_MINUTES 0x14
+#define WM8350_ALARM_HOURS_DAY 0x15
+#define WM8350_ALARM_DATE_MONTH 0x16
+#define WM8350_RTC_TIME_CONTROL 0x17
+
+/*
+ * R16 (0x10) - RTC Seconds/Minutes
+ */
+#define WM8350_RTC_MINS_MASK 0x7F00
+#define WM8350_RTC_MINS_SHIFT 8
+#define WM8350_RTC_SECS_MASK 0x007F
+#define WM8350_RTC_SECS_SHIFT 0
+
+/*
+ * R17 (0x11) - RTC Hours/Day
+ */
+#define WM8350_RTC_DAY_MASK 0x0700
+#define WM8350_RTC_DAY_SHIFT 8
+#define WM8350_RTC_HPM_MASK 0x0020
+#define WM8350_RTC_HPM_SHIFT 5
+#define WM8350_RTC_HRS_MASK 0x001F
+#define WM8350_RTC_HRS_SHIFT 0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_DAY_SUN 1
+#define WM8350_RTC_DAY_MON 2
+#define WM8350_RTC_DAY_TUE 3
+#define WM8350_RTC_DAY_WED 4
+#define WM8350_RTC_DAY_THU 5
+#define WM8350_RTC_DAY_FRI 6
+#define WM8350_RTC_DAY_SAT 7
+
+#define WM8350_RTC_HPM_AM 0
+#define WM8350_RTC_HPM_PM 1
+
+/*
+ * R18 (0x12) - RTC Date/Month
+ */
+#define WM8350_RTC_MTH_MASK 0x1F00
+#define WM8350_RTC_MTH_SHIFT 8
+#define WM8350_RTC_DATE_MASK 0x003F
+#define WM8350_RTC_DATE_SHIFT 0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_MTH_JAN 1
+#define WM8350_RTC_MTH_FEB 2
+#define WM8350_RTC_MTH_MAR 3
+#define WM8350_RTC_MTH_APR 4
+#define WM8350_RTC_MTH_MAY 5
+#define WM8350_RTC_MTH_JUN 6
+#define WM8350_RTC_MTH_JUL 7
+#define WM8350_RTC_MTH_AUG 8
+#define WM8350_RTC_MTH_SEP 9
+#define WM8350_RTC_MTH_OCT 10
+#define WM8350_RTC_MTH_NOV 11
+#define WM8350_RTC_MTH_DEC 12
+#define WM8350_RTC_MTH_JAN_BCD 0x01
+#define WM8350_RTC_MTH_FEB_BCD 0x02
+#define WM8350_RTC_MTH_MAR_BCD 0x03
+#define WM8350_RTC_MTH_APR_BCD 0x04
+#define WM8350_RTC_MTH_MAY_BCD 0x05
+#define WM8350_RTC_MTH_JUN_BCD 0x06
+#define WM8350_RTC_MTH_JUL_BCD 0x07
+#define WM8350_RTC_MTH_AUG_BCD 0x08
+#define WM8350_RTC_MTH_SEP_BCD 0x09
+#define WM8350_RTC_MTH_OCT_BCD 0x10
+#define WM8350_RTC_MTH_NOV_BCD 0x11
+#define WM8350_RTC_MTH_DEC_BCD 0x12
+
+/*
+ * R19 (0x13) - RTC Year
+ */
+#define WM8350_RTC_YHUNDREDS_MASK 0x3F00
+#define WM8350_RTC_YHUNDREDS_SHIFT 8
+#define WM8350_RTC_YUNITS_MASK 0x00FF
+#define WM8350_RTC_YUNITS_SHIFT 0
+
+/*
+ * R20 (0x14) - Alarm Seconds/Minutes
+ */
+#define WM8350_RTC_ALMMINS_MASK 0x7F00
+#define WM8350_RTC_ALMMINS_SHIFT 8
+#define WM8350_RTC_ALMSECS_MASK 0x007F
+#define WM8350_RTC_ALMSECS_SHIFT 0
+
+/* Bit values for R20 (0x14) */
+#define WM8350_RTC_ALMMINS_DONT_CARE -1
+#define WM8350_RTC_ALMSECS_DONT_CARE -1
+
+/*
+ * R21 (0x15) - Alarm Hours/Day
+ */
+#define WM8350_RTC_ALMDAY_MASK 0x0F00
+#define WM8350_RTC_ALMDAY_SHIFT 8
+#define WM8350_RTC_ALMHPM_MASK 0x0020
+#define WM8350_RTC_ALMHPM_SHIFT 5
+#define WM8350_RTC_ALMHRS_MASK 0x001F
+#define WM8350_RTC_ALMHRS_SHIFT 0
+
+/* Bit values for R21 (0x15) */
+#define WM8350_RTC_ALMDAY_DONT_CARE -1
+#define WM8350_RTC_ALMDAY_SUN 1
+#define WM8350_RTC_ALMDAY_MON 2
+#define WM8350_RTC_ALMDAY_TUE 3
+#define WM8350_RTC_ALMDAY_WED 4
+#define WM8350_RTC_ALMDAY_THU 5
+#define WM8350_RTC_ALMDAY_FRI 6
+#define WM8350_RTC_ALMDAY_SAT 7
+
+#define WM8350_RTC_ALMHPM_AM 0
+#define WM8350_RTC_ALMHPM_PM 1
+
+#define WM8350_RTC_ALMHRS_DONT_CARE -1
+
+/*
+ * R22 (0x16) - Alarm Date/Month
+ */
+#define WM8350_RTC_ALMMTH_MASK 0x1F00
+#define WM8350_RTC_ALMMTH_SHIFT 8
+#define WM8350_RTC_ALMDATE_MASK 0x003F
+#define WM8350_RTC_ALMDATE_SHIFT 0
+
+/* Bit values for R22 (0x16) */
+#define WM8350_RTC_ALMDATE_DONT_CARE -1
+
+#define WM8350_RTC_ALMMTH_DONT_CARE -1
+#define WM8350_RTC_ALMMTH_JAN 1
+#define WM8350_RTC_ALMMTH_FEB 2
+#define WM8350_RTC_ALMMTH_MAR 3
+#define WM8350_RTC_ALMMTH_APR 4
+#define WM8350_RTC_ALMMTH_MAY 5
+#define WM8350_RTC_ALMMTH_JUN 6
+#define WM8350_RTC_ALMMTH_JUL 7
+#define WM8350_RTC_ALMMTH_AUG 8
+#define WM8350_RTC_ALMMTH_SEP 9
+#define WM8350_RTC_ALMMTH_OCT 10
+#define WM8350_RTC_ALMMTH_NOV 11
+#define WM8350_RTC_ALMMTH_DEC 12
+#define WM8350_RTC_ALMMTH_JAN_BCD 0x01
+#define WM8350_RTC_ALMMTH_FEB_BCD 0x02
+#define WM8350_RTC_ALMMTH_MAR_BCD 0x03
+#define WM8350_RTC_ALMMTH_APR_BCD 0x04
+#define WM8350_RTC_ALMMTH_MAY_BCD 0x05
+#define WM8350_RTC_ALMMTH_JUN_BCD 0x06
+#define WM8350_RTC_ALMMTH_JUL_BCD 0x07
+#define WM8350_RTC_ALMMTH_AUG_BCD 0x08
+#define WM8350_RTC_ALMMTH_SEP_BCD 0x09
+#define WM8350_RTC_ALMMTH_OCT_BCD 0x10
+#define WM8350_RTC_ALMMTH_NOV_BCD 0x11
+#define WM8350_RTC_ALMMTH_DEC_BCD 0x12
+
+/*
+ * R23 (0x17) - RTC Time Control
+ */
+#define WM8350_RTC_BCD 0x8000
+#define WM8350_RTC_BCD_MASK 0x8000
+#define WM8350_RTC_BCD_SHIFT 15
+#define WM8350_RTC_12HR 0x4000
+#define WM8350_RTC_12HR_MASK 0x4000
+#define WM8350_RTC_12HR_SHIFT 14
+#define WM8350_RTC_DST 0x2000
+#define WM8350_RTC_DST_MASK 0x2000
+#define WM8350_RTC_DST_SHIFT 13
+#define WM8350_RTC_SET 0x0800
+#define WM8350_RTC_SET_MASK 0x0800
+#define WM8350_RTC_SET_SHIFT 11
+#define WM8350_RTC_STS 0x0400
+#define WM8350_RTC_STS_MASK 0x0400
+#define WM8350_RTC_STS_SHIFT 10
+#define WM8350_RTC_ALMSET 0x0200
+#define WM8350_RTC_ALMSET_MASK 0x0200
+#define WM8350_RTC_ALMSET_SHIFT 9
+#define WM8350_RTC_ALMSTS 0x0100
+#define WM8350_RTC_ALMSTS_MASK 0x0100
+#define WM8350_RTC_ALMSTS_SHIFT 8
+#define WM8350_RTC_PINT 0x0070
+#define WM8350_RTC_PINT_MASK 0x0070
+#define WM8350_RTC_PINT_SHIFT 4
+#define WM8350_RTC_DSW 0x000F
+#define WM8350_RTC_DSW_MASK 0x000F
+#define WM8350_RTC_DSW_SHIFT 0
+
+/* Bit values for R23 (0x17) */
+#define WM8350_RTC_BCD_BINARY 0
+#define WM8350_RTC_BCD_BCD 1
+
+#define WM8350_RTC_12HR_24HR 0
+#define WM8350_RTC_12HR_12HR 1
+
+#define WM8350_RTC_DST_DISABLED 0
+#define WM8350_RTC_DST_ENABLED 1
+
+#define WM8350_RTC_SET_RUN 0
+#define WM8350_RTC_SET_SET 1
+
+#define WM8350_RTC_STS_RUNNING 0
+#define WM8350_RTC_STS_STOPPED 1
+
+#define WM8350_RTC_ALMSET_RUN 0
+#define WM8350_RTC_ALMSET_SET 1
+
+#define WM8350_RTC_ALMSTS_RUNNING 0
+#define WM8350_RTC_ALMSTS_STOPPED 1
+
+#define WM8350_RTC_PINT_DISABLED 0
+#define WM8350_RTC_PINT_SECS 1
+#define WM8350_RTC_PINT_MINS 2
+#define WM8350_RTC_PINT_HRS 3
+#define WM8350_RTC_PINT_DAYS 4
+#define WM8350_RTC_PINT_MTHS 5
+
+#define WM8350_RTC_DSW_DISABLED 0
+#define WM8350_RTC_DSW_1HZ 1
+#define WM8350_RTC_DSW_2HZ 2
+#define WM8350_RTC_DSW_4HZ 3
+#define WM8350_RTC_DSW_8HZ 4
+#define WM8350_RTC_DSW_16HZ 5
+#define WM8350_RTC_DSW_32HZ 6
+#define WM8350_RTC_DSW_64HZ 7
+#define WM8350_RTC_DSW_128HZ 8
+#define WM8350_RTC_DSW_256HZ 9
+#define WM8350_RTC_DSW_512HZ 10
+#define WM8350_RTC_DSW_1024HZ 11
+
+/*
+ * R218 (0xDA) - RTC Tick Control
+ */
+#define WM8350_RTC_TICKSTS 0x4000
+#define WM8350_RTC_CLKSRC 0x2000
+#define WM8350_RTC_TRIM_MASK 0x03FF
+
+/*
+ * RTC Interrupts.
+ */
+#define WM8350_IRQ_RTC_PER 7
+#define WM8350_IRQ_RTC_SEC 8
+#define WM8350_IRQ_RTC_ALM 9
+
+struct wm8350_rtc {
+ struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/supply.h b/include/linux/mfd/wm8350/supply.h
new file mode 100644
index 00000000000..1c8f3cde79b
--- /dev/null
+++ b/include/linux/mfd/wm8350/supply.h
@@ -0,0 +1,111 @@
+/*
+ * supply.h -- Power Supply Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_SUPPLY_H_
+#define __LINUX_MFD_WM8350_SUPPLY_H_
+
+#include <linux/platform_device.h>
+
+/*
+ * Charger registers
+ */
+#define WM8350_BATTERY_CHARGER_CONTROL_1 0xA8
+#define WM8350_BATTERY_CHARGER_CONTROL_2 0xA9
+#define WM8350_BATTERY_CHARGER_CONTROL_3 0xAA
+
+/*
+ * R168 (0xA8) - Battery Charger Control 1
+ */
+#define WM8350_CHG_ENA_R168 0x8000
+#define WM8350_CHG_THR 0x2000
+#define WM8350_CHG_EOC_SEL_MASK 0x1C00
+#define WM8350_CHG_TRICKLE_TEMP_CHOKE 0x0200
+#define WM8350_CHG_TRICKLE_USB_CHOKE 0x0100
+#define WM8350_CHG_RECOVER_T 0x0080
+#define WM8350_CHG_END_ACT 0x0040
+#define WM8350_CHG_FAST 0x0020
+#define WM8350_CHG_FAST_USB_THROTTLE 0x0010
+#define WM8350_CHG_NTC_MON 0x0008
+#define WM8350_CHG_BATT_HOT_MON 0x0004
+#define WM8350_CHG_BATT_COLD_MON 0x0002
+#define WM8350_CHG_CHIP_TEMP_MON 0x0001
+
+/*
+ * R169 (0xA9) - Battery Charger Control 2
+ */
+#define WM8350_CHG_ACTIVE 0x8000
+#define WM8350_CHG_PAUSE 0x4000
+#define WM8350_CHG_STS_MASK 0x3000
+#define WM8350_CHG_TIME_MASK 0x0F00
+#define WM8350_CHG_MASK_WALL_FB 0x0080
+#define WM8350_CHG_TRICKLE_SEL 0x0040
+#define WM8350_CHG_VSEL_MASK 0x0030
+#define WM8350_CHG_ISEL_MASK 0x000F
+#define WM8350_CHG_STS_OFF 0x0000
+#define WM8350_CHG_STS_TRICKLE 0x1000
+#define WM8350_CHG_STS_FAST 0x2000
+
+/*
+ * R170 (0xAA) - Battery Charger Control 3
+ */
+#define WM8350_CHG_THROTTLE_T_MASK 0x0060
+#define WM8350_CHG_SMART 0x0010
+#define WM8350_CHG_TIMER_ADJT_MASK 0x000F
+
+/*
+ * Charger Interrupts
+ */
+#define WM8350_IRQ_CHG_BAT_HOT 0
+#define WM8350_IRQ_CHG_BAT_COLD 1
+#define WM8350_IRQ_CHG_BAT_FAIL 2
+#define WM8350_IRQ_CHG_TO 3
+#define WM8350_IRQ_CHG_END 4
+#define WM8350_IRQ_CHG_START 5
+#define WM8350_IRQ_CHG_FAST_RDY 6
+#define WM8350_IRQ_CHG_VBATT_LT_3P9 10
+#define WM8350_IRQ_CHG_VBATT_LT_3P1 11
+#define WM8350_IRQ_CHG_VBATT_LT_2P85 12
+
+/*
+ * Charger Policy
+ */
+#define WM8350_CHG_TRICKLE_50mA (0 << 6)
+#define WM8350_CHG_TRICKLE_100mA (1 << 6)
+#define WM8350_CHG_4_05V (0 << 4)
+#define WM8350_CHG_4_10V (1 << 4)
+#define WM8350_CHG_4_15V (2 << 4)
+#define WM8350_CHG_4_20V (3 << 4)
+#define WM8350_CHG_FAST_LIMIT_mA(x) ((x / 50) & 0xf)
+#define WM8350_CHG_EOC_mA(x) (((x - 10) & 0x7) << 10)
+#define WM8350_CHG_TRICKLE_3_1V (0 << 13)
+#define WM8350_CHG_TRICKLE_3_9V (1 << 13)
+
+/*
+ * Supply Registers.
+ */
+#define WM8350_USB_VOLTAGE_READBACK 0x9C
+#define WM8350_LINE_VOLTAGE_READBACK 0x9D
+#define WM8350_BATT_VOLTAGE_READBACK 0x9E
+
+/*
+ * Supply Interrupts.
+ */
+#define WM8350_IRQ_USB_LIMIT 15
+#define WM8350_IRQ_EXT_USB_FB 36
+#define WM8350_IRQ_EXT_WALL_FB 37
+#define WM8350_IRQ_EXT_BAT_FB 38
+
+struct wm8350_power {
+ struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8350/wdt.h b/include/linux/mfd/wm8350/wdt.h
new file mode 100644
index 00000000000..f6135b5e5ef
--- /dev/null
+++ b/include/linux/mfd/wm8350/wdt.h
@@ -0,0 +1,28 @@
+/*
+ * wdt.h -- Watchdog Driver for Wolfson WM8350 PMIC
+ *
+ * Copyright 2007, 2008 Wolfson Microelectronics PLC
+ *
+ * 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 __LINUX_MFD_WM8350_WDT_H_
+#define __LINUX_MFD_WM8350_WDT_H_
+
+#include <linux/platform_device.h>
+
+#define WM8350_WDOG_HIB_MODE 0x0080
+#define WM8350_WDOG_DEBUG 0x0040
+#define WM8350_WDOG_MODE_MASK 0x0030
+#define WM8350_WDOG_TO_MASK 0x0007
+
+#define WM8350_IRQ_SYS_WDOG_TO 24
+
+struct wm8350_wdt {
+ struct platform_device *pdev;
+};
+
+#endif
diff --git a/include/linux/mfd/wm8400-audio.h b/include/linux/mfd/wm8400-audio.h
new file mode 100644
index 00000000000..b6640e01804
--- /dev/null
+++ b/include/linux/mfd/wm8400-audio.h
@@ -0,0 +1,1186 @@
+/*
+ * wm8400 private definitions for audio
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * 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 __LINUX_MFD_WM8400_AUDIO_H
+#define __LINUX_MFD_WM8400_AUDIO_H
+
+#include <linux/mfd/wm8400-audio.h>
+
+/*
+ * R2 (0x02) - Power Management (1)
+ */
+#define WM8400_CODEC_ENA 0x8000 /* CODEC_ENA */
+#define WM8400_CODEC_ENA_MASK 0x8000 /* CODEC_ENA */
+#define WM8400_CODEC_ENA_SHIFT 15 /* CODEC_ENA */
+#define WM8400_CODEC_ENA_WIDTH 1 /* CODEC_ENA */
+#define WM8400_SYSCLK_ENA 0x4000 /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_MASK 0x4000 /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_SHIFT 14 /* SYSCLK_ENA */
+#define WM8400_SYSCLK_ENA_WIDTH 1 /* SYSCLK_ENA */
+#define WM8400_SPK_MIX_ENA 0x2000 /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_MASK 0x2000 /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_SHIFT 13 /* SPK_MIX_ENA */
+#define WM8400_SPK_MIX_ENA_WIDTH 1 /* SPK_MIX_ENA */
+#define WM8400_SPK_ENA 0x1000 /* SPK_ENA */
+#define WM8400_SPK_ENA_MASK 0x1000 /* SPK_ENA */
+#define WM8400_SPK_ENA_SHIFT 12 /* SPK_ENA */
+#define WM8400_SPK_ENA_WIDTH 1 /* SPK_ENA */
+#define WM8400_OUT3_ENA 0x0800 /* OUT3_ENA */
+#define WM8400_OUT3_ENA_MASK 0x0800 /* OUT3_ENA */
+#define WM8400_OUT3_ENA_SHIFT 11 /* OUT3_ENA */
+#define WM8400_OUT3_ENA_WIDTH 1 /* OUT3_ENA */
+#define WM8400_OUT4_ENA 0x0400 /* OUT4_ENA */
+#define WM8400_OUT4_ENA_MASK 0x0400 /* OUT4_ENA */
+#define WM8400_OUT4_ENA_SHIFT 10 /* OUT4_ENA */
+#define WM8400_OUT4_ENA_WIDTH 1 /* OUT4_ENA */
+#define WM8400_LOUT_ENA 0x0200 /* LOUT_ENA */
+#define WM8400_LOUT_ENA_MASK 0x0200 /* LOUT_ENA */
+#define WM8400_LOUT_ENA_SHIFT 9 /* LOUT_ENA */
+#define WM8400_LOUT_ENA_WIDTH 1 /* LOUT_ENA */
+#define WM8400_ROUT_ENA 0x0100 /* ROUT_ENA */
+#define WM8400_ROUT_ENA_MASK 0x0100 /* ROUT_ENA */
+#define WM8400_ROUT_ENA_SHIFT 8 /* ROUT_ENA */
+#define WM8400_ROUT_ENA_WIDTH 1 /* ROUT_ENA */
+#define WM8400_MIC1BIAS_ENA 0x0010 /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_MASK 0x0010 /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_SHIFT 4 /* MIC1BIAS_ENA */
+#define WM8400_MIC1BIAS_ENA_WIDTH 1 /* MIC1BIAS_ENA */
+#define WM8400_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_SHIFT 1 /* VMID_MODE - [2:1] */
+#define WM8400_VMID_MODE_WIDTH 2 /* VMID_MODE - [2:1] */
+#define WM8400_VREF_ENA 0x0001 /* VREF_ENA */
+#define WM8400_VREF_ENA_MASK 0x0001 /* VREF_ENA */
+#define WM8400_VREF_ENA_SHIFT 0 /* VREF_ENA */
+#define WM8400_VREF_ENA_WIDTH 1 /* VREF_ENA */
+
+/*
+ * R3 (0x03) - Power Management (2)
+ */
+#define WM8400_FLL_ENA 0x8000 /* FLL_ENA */
+#define WM8400_FLL_ENA_MASK 0x8000 /* FLL_ENA */
+#define WM8400_FLL_ENA_SHIFT 15 /* FLL_ENA */
+#define WM8400_FLL_ENA_WIDTH 1 /* FLL_ENA */
+#define WM8400_TSHUT_ENA 0x4000 /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */
+#define WM8400_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */
+#define WM8400_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */
+#define WM8400_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */
+#define WM8400_OPCLK_ENA 0x0800 /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_MASK 0x0800 /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_SHIFT 11 /* OPCLK_ENA */
+#define WM8400_OPCLK_ENA_WIDTH 1 /* OPCLK_ENA */
+#define WM8400_AINL_ENA 0x0200 /* AINL_ENA */
+#define WM8400_AINL_ENA_MASK 0x0200 /* AINL_ENA */
+#define WM8400_AINL_ENA_SHIFT 9 /* AINL_ENA */
+#define WM8400_AINL_ENA_WIDTH 1 /* AINL_ENA */
+#define WM8400_AINR_ENA 0x0100 /* AINR_ENA */
+#define WM8400_AINR_ENA_MASK 0x0100 /* AINR_ENA */
+#define WM8400_AINR_ENA_SHIFT 8 /* AINR_ENA */
+#define WM8400_AINR_ENA_WIDTH 1 /* AINR_ENA */
+#define WM8400_LIN34_ENA 0x0080 /* LIN34_ENA */
+#define WM8400_LIN34_ENA_MASK 0x0080 /* LIN34_ENA */
+#define WM8400_LIN34_ENA_SHIFT 7 /* LIN34_ENA */
+#define WM8400_LIN34_ENA_WIDTH 1 /* LIN34_ENA */
+#define WM8400_LIN12_ENA 0x0040 /* LIN12_ENA */
+#define WM8400_LIN12_ENA_MASK 0x0040 /* LIN12_ENA */
+#define WM8400_LIN12_ENA_SHIFT 6 /* LIN12_ENA */
+#define WM8400_LIN12_ENA_WIDTH 1 /* LIN12_ENA */
+#define WM8400_RIN34_ENA 0x0020 /* RIN34_ENA */
+#define WM8400_RIN34_ENA_MASK 0x0020 /* RIN34_ENA */
+#define WM8400_RIN34_ENA_SHIFT 5 /* RIN34_ENA */
+#define WM8400_RIN34_ENA_WIDTH 1 /* RIN34_ENA */
+#define WM8400_RIN12_ENA 0x0010 /* RIN12_ENA */
+#define WM8400_RIN12_ENA_MASK 0x0010 /* RIN12_ENA */
+#define WM8400_RIN12_ENA_SHIFT 4 /* RIN12_ENA */
+#define WM8400_RIN12_ENA_WIDTH 1 /* RIN12_ENA */
+#define WM8400_ADCL_ENA 0x0002 /* ADCL_ENA */
+#define WM8400_ADCL_ENA_MASK 0x0002 /* ADCL_ENA */
+#define WM8400_ADCL_ENA_SHIFT 1 /* ADCL_ENA */
+#define WM8400_ADCL_ENA_WIDTH 1 /* ADCL_ENA */
+#define WM8400_ADCR_ENA 0x0001 /* ADCR_ENA */
+#define WM8400_ADCR_ENA_MASK 0x0001 /* ADCR_ENA */
+#define WM8400_ADCR_ENA_SHIFT 0 /* ADCR_ENA */
+#define WM8400_ADCR_ENA_WIDTH 1 /* ADCR_ENA */
+
+/*
+ * R4 (0x04) - Power Management (3)
+ */
+#define WM8400_LON_ENA 0x2000 /* LON_ENA */
+#define WM8400_LON_ENA_MASK 0x2000 /* LON_ENA */
+#define WM8400_LON_ENA_SHIFT 13 /* LON_ENA */
+#define WM8400_LON_ENA_WIDTH 1 /* LON_ENA */
+#define WM8400_LOP_ENA 0x1000 /* LOP_ENA */
+#define WM8400_LOP_ENA_MASK 0x1000 /* LOP_ENA */
+#define WM8400_LOP_ENA_SHIFT 12 /* LOP_ENA */
+#define WM8400_LOP_ENA_WIDTH 1 /* LOP_ENA */
+#define WM8400_RON_ENA 0x0800 /* RON_ENA */
+#define WM8400_RON_ENA_MASK 0x0800 /* RON_ENA */
+#define WM8400_RON_ENA_SHIFT 11 /* RON_ENA */
+#define WM8400_RON_ENA_WIDTH 1 /* RON_ENA */
+#define WM8400_ROP_ENA 0x0400 /* ROP_ENA */
+#define WM8400_ROP_ENA_MASK 0x0400 /* ROP_ENA */
+#define WM8400_ROP_ENA_SHIFT 10 /* ROP_ENA */
+#define WM8400_ROP_ENA_WIDTH 1 /* ROP_ENA */
+#define WM8400_LOPGA_ENA 0x0080 /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_MASK 0x0080 /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_SHIFT 7 /* LOPGA_ENA */
+#define WM8400_LOPGA_ENA_WIDTH 1 /* LOPGA_ENA */
+#define WM8400_ROPGA_ENA 0x0040 /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_MASK 0x0040 /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_SHIFT 6 /* ROPGA_ENA */
+#define WM8400_ROPGA_ENA_WIDTH 1 /* ROPGA_ENA */
+#define WM8400_LOMIX_ENA 0x0020 /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_MASK 0x0020 /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_SHIFT 5 /* LOMIX_ENA */
+#define WM8400_LOMIX_ENA_WIDTH 1 /* LOMIX_ENA */
+#define WM8400_ROMIX_ENA 0x0010 /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_MASK 0x0010 /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_SHIFT 4 /* ROMIX_ENA */
+#define WM8400_ROMIX_ENA_WIDTH 1 /* ROMIX_ENA */
+#define WM8400_DACL_ENA 0x0002 /* DACL_ENA */
+#define WM8400_DACL_ENA_MASK 0x0002 /* DACL_ENA */
+#define WM8400_DACL_ENA_SHIFT 1 /* DACL_ENA */
+#define WM8400_DACL_ENA_WIDTH 1 /* DACL_ENA */
+#define WM8400_DACR_ENA 0x0001 /* DACR_ENA */
+#define WM8400_DACR_ENA_MASK 0x0001 /* DACR_ENA */
+#define WM8400_DACR_ENA_SHIFT 0 /* DACR_ENA */
+#define WM8400_DACR_ENA_WIDTH 1 /* DACR_ENA */
+
+/*
+ * R5 (0x05) - Audio Interface (1)
+ */
+#define WM8400_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_MASK 0x8000 /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_SHIFT 15 /* AIFADCL_SRC */
+#define WM8400_AIFADCL_SRC_WIDTH 1 /* AIFADCL_SRC */
+#define WM8400_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_MASK 0x4000 /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_SHIFT 14 /* AIFADCR_SRC */
+#define WM8400_AIFADCR_SRC_WIDTH 1 /* AIFADCR_SRC */
+#define WM8400_AIFADC_TDM 0x2000 /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_MASK 0x2000 /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_SHIFT 13 /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_WIDTH 1 /* AIFADC_TDM */
+#define WM8400_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_MASK 0x1000 /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_SHIFT 12 /* AIFADC_TDM_CHAN */
+#define WM8400_AIFADC_TDM_CHAN_WIDTH 1 /* AIFADC_TDM_CHAN */
+#define WM8400_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_MASK 0x0100 /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_SHIFT 8 /* AIF_BCLK_INV */
+#define WM8400_AIF_BCLK_INV_WIDTH 1 /* AIF_BCLK_INV */
+#define WM8400_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_MASK 0x0080 /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_SHIFT 7 /* AIF_LRCLK_INV */
+#define WM8400_AIF_LRCLK_INV_WIDTH 1 /* AIF_LRCLK_INV */
+#define WM8400_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_SHIFT 5 /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_WIDTH 2 /* AIF_WL - [6:5] */
+#define WM8400_AIF_WL_16BITS (0 << 5)
+#define WM8400_AIF_WL_20BITS (1 << 5)
+#define WM8400_AIF_WL_24BITS (2 << 5)
+#define WM8400_AIF_WL_32BITS (3 << 5)
+#define WM8400_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_SHIFT 3 /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_WIDTH 2 /* AIF_FMT - [4:3] */
+#define WM8400_AIF_FMT_RIGHTJ (0 << 3)
+#define WM8400_AIF_FMT_LEFTJ (1 << 3)
+#define WM8400_AIF_FMT_I2S (2 << 3)
+#define WM8400_AIF_FMT_DSP (3 << 3)
+
+/*
+ * R6 (0x06) - Audio Interface (2)
+ */
+#define WM8400_DACL_SRC 0x8000 /* DACL_SRC */
+#define WM8400_DACL_SRC_MASK 0x8000 /* DACL_SRC */
+#define WM8400_DACL_SRC_SHIFT 15 /* DACL_SRC */
+#define WM8400_DACL_SRC_WIDTH 1 /* DACL_SRC */
+#define WM8400_DACR_SRC 0x4000 /* DACR_SRC */
+#define WM8400_DACR_SRC_MASK 0x4000 /* DACR_SRC */
+#define WM8400_DACR_SRC_SHIFT 14 /* DACR_SRC */
+#define WM8400_DACR_SRC_WIDTH 1 /* DACR_SRC */
+#define WM8400_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_MASK 0x2000 /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_SHIFT 13 /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_WIDTH 1 /* AIFDAC_TDM */
+#define WM8400_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_MASK 0x1000 /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_SHIFT 12 /* AIFDAC_TDM_CHAN */
+#define WM8400_AIFDAC_TDM_CHAN_WIDTH 1 /* AIFDAC_TDM_CHAN */
+#define WM8400_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_SHIFT 10 /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_BOOST_WIDTH 2 /* DAC_BOOST - [11:10] */
+#define WM8400_DAC_COMP 0x0010 /* DAC_COMP */
+#define WM8400_DAC_COMP_MASK 0x0010 /* DAC_COMP */
+#define WM8400_DAC_COMP_SHIFT 4 /* DAC_COMP */
+#define WM8400_DAC_COMP_WIDTH 1 /* DAC_COMP */
+#define WM8400_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_MASK 0x0008 /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_SHIFT 3 /* DAC_COMPMODE */
+#define WM8400_DAC_COMPMODE_WIDTH 1 /* DAC_COMPMODE */
+#define WM8400_ADC_COMP 0x0004 /* ADC_COMP */
+#define WM8400_ADC_COMP_MASK 0x0004 /* ADC_COMP */
+#define WM8400_ADC_COMP_SHIFT 2 /* ADC_COMP */
+#define WM8400_ADC_COMP_WIDTH 1 /* ADC_COMP */
+#define WM8400_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_MASK 0x0002 /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_SHIFT 1 /* ADC_COMPMODE */
+#define WM8400_ADC_COMPMODE_WIDTH 1 /* ADC_COMPMODE */
+#define WM8400_LOOPBACK 0x0001 /* LOOPBACK */
+#define WM8400_LOOPBACK_MASK 0x0001 /* LOOPBACK */
+#define WM8400_LOOPBACK_SHIFT 0 /* LOOPBACK */
+#define WM8400_LOOPBACK_WIDTH 1 /* LOOPBACK */
+
+/*
+ * R7 (0x07) - Clocking (1)
+ */
+#define WM8400_TOCLK_RATE 0x8000 /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_MASK 0x8000 /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_SHIFT 15 /* TOCLK_RATE */
+#define WM8400_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */
+#define WM8400_TOCLK_ENA 0x4000 /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_MASK 0x4000 /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_SHIFT 14 /* TOCLK_ENA */
+#define WM8400_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
+#define WM8400_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_SHIFT 9 /* OPCLKDIV - [12:9] */
+#define WM8400_OPCLKDIV_WIDTH 4 /* OPCLKDIV - [12:9] */
+#define WM8400_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_SHIFT 6 /* DCLKDIV - [8:6] */
+#define WM8400_DCLKDIV_WIDTH 3 /* DCLKDIV - [8:6] */
+#define WM8400_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_SHIFT 1 /* BCLK_DIV - [4:1] */
+#define WM8400_BCLK_DIV_WIDTH 4 /* BCLK_DIV - [4:1] */
+
+/*
+ * R8 (0x08) - Clocking (2)
+ */
+#define WM8400_MCLK_SRC 0x8000 /* MCLK_SRC */
+#define WM8400_MCLK_SRC_MASK 0x8000 /* MCLK_SRC */
+#define WM8400_MCLK_SRC_SHIFT 15 /* MCLK_SRC */
+#define WM8400_MCLK_SRC_WIDTH 1 /* MCLK_SRC */
+#define WM8400_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_MASK 0x4000 /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_SHIFT 14 /* SYSCLK_SRC */
+#define WM8400_SYSCLK_SRC_WIDTH 1 /* SYSCLK_SRC */
+#define WM8400_CLK_FORCE 0x2000 /* CLK_FORCE */
+#define WM8400_CLK_FORCE_MASK 0x2000 /* CLK_FORCE */
+#define WM8400_CLK_FORCE_SHIFT 13 /* CLK_FORCE */
+#define WM8400_CLK_FORCE_WIDTH 1 /* CLK_FORCE */
+#define WM8400_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_SHIFT 11 /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_DIV_WIDTH 2 /* MCLK_DIV - [12:11] */
+#define WM8400_MCLK_INV 0x0400 /* MCLK_INV */
+#define WM8400_MCLK_INV_MASK 0x0400 /* MCLK_INV */
+#define WM8400_MCLK_INV_SHIFT 10 /* MCLK_INV */
+#define WM8400_MCLK_INV_WIDTH 1 /* MCLK_INV */
+#define WM8400_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_SHIFT 5 /* ADC_CLKDIV - [7:5] */
+#define WM8400_ADC_CLKDIV_WIDTH 3 /* ADC_CLKDIV - [7:5] */
+#define WM8400_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_SHIFT 2 /* DAC_CLKDIV - [4:2] */
+#define WM8400_DAC_CLKDIV_WIDTH 3 /* DAC_CLKDIV - [4:2] */
+
+/*
+ * R9 (0x09) - Audio Interface (3)
+ */
+#define WM8400_AIF_MSTR1 0x8000 /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_MASK 0x8000 /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_SHIFT 15 /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR1_WIDTH 1 /* AIF_MSTR1 */
+#define WM8400_AIF_MSTR2 0x4000 /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_MASK 0x4000 /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_SHIFT 14 /* AIF_MSTR2 */
+#define WM8400_AIF_MSTR2_WIDTH 1 /* AIF_MSTR2 */
+#define WM8400_AIF_SEL 0x2000 /* AIF_SEL */
+#define WM8400_AIF_SEL_MASK 0x2000 /* AIF_SEL */
+#define WM8400_AIF_SEL_SHIFT 13 /* AIF_SEL */
+#define WM8400_AIF_SEL_WIDTH 1 /* AIF_SEL */
+#define WM8400_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_MASK 0x0800 /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_SHIFT 11 /* ADCLRC_DIR */
+#define WM8400_ADCLRC_DIR_WIDTH 1 /* ADCLRC_DIR */
+#define WM8400_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_SHIFT 0 /* ADCLRC_RATE - [10:0] */
+#define WM8400_ADCLRC_RATE_WIDTH 11 /* ADCLRC_RATE - [10:0] */
+
+/*
+ * R10 (0x0A) - Audio Interface (4)
+ */
+#define WM8400_ALRCGPIO1 0x8000 /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_MASK 0x8000 /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_SHIFT 15 /* ALRCGPIO1 */
+#define WM8400_ALRCGPIO1_WIDTH 1 /* ALRCGPIO1 */
+#define WM8400_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_MASK 0x4000 /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_SHIFT 14 /* ALRCBGPIO6 */
+#define WM8400_ALRCBGPIO6_WIDTH 1 /* ALRCBGPIO6 */
+#define WM8400_AIF_TRIS 0x2000 /* AIF_TRIS */
+#define WM8400_AIF_TRIS_MASK 0x2000 /* AIF_TRIS */
+#define WM8400_AIF_TRIS_SHIFT 13 /* AIF_TRIS */
+#define WM8400_AIF_TRIS_WIDTH 1 /* AIF_TRIS */
+#define WM8400_DACLRC_DIR 0x0800 /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_MASK 0x0800 /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_SHIFT 11 /* DACLRC_DIR */
+#define WM8400_DACLRC_DIR_WIDTH 1 /* DACLRC_DIR */
+#define WM8400_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_SHIFT 0 /* DACLRC_RATE - [10:0] */
+#define WM8400_DACLRC_RATE_WIDTH 11 /* DACLRC_RATE - [10:0] */
+
+/*
+ * R11 (0x0B) - DAC CTRL
+ */
+#define WM8400_DAC_SDMCLK_RATE 0x2000 /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_MASK 0x2000 /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_SHIFT 13 /* DAC_SDMCLK_RATE */
+#define WM8400_DAC_SDMCLK_RATE_WIDTH 1 /* DAC_SDMCLK_RATE */
+#define WM8400_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_MASK 0x0400 /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_SHIFT 10 /* AIF_LRCLKRATE */
+#define WM8400_AIF_LRCLKRATE_WIDTH 1 /* AIF_LRCLKRATE */
+#define WM8400_DAC_MONO 0x0200 /* DAC_MONO */
+#define WM8400_DAC_MONO_MASK 0x0200 /* DAC_MONO */
+#define WM8400_DAC_MONO_SHIFT 9 /* DAC_MONO */
+#define WM8400_DAC_MONO_WIDTH 1 /* DAC_MONO */
+#define WM8400_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_MASK 0x0100 /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_SHIFT 8 /* DAC_SB_FILT */
+#define WM8400_DAC_SB_FILT_WIDTH 1 /* DAC_SB_FILT */
+#define WM8400_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_MASK 0x0080 /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_SHIFT 7 /* DAC_MUTERATE */
+#define WM8400_DAC_MUTERATE_WIDTH 1 /* DAC_MUTERATE */
+#define WM8400_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_MASK 0x0040 /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_SHIFT 6 /* DAC_MUTEMODE */
+#define WM8400_DAC_MUTEMODE_WIDTH 1 /* DAC_MUTEMODE */
+#define WM8400_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */
+#define WM8400_DEEMP_SHIFT 4 /* DEEMP - [5:4] */
+#define WM8400_DEEMP_WIDTH 2 /* DEEMP - [5:4] */
+#define WM8400_DAC_MUTE 0x0004 /* DAC_MUTE */
+#define WM8400_DAC_MUTE_MASK 0x0004 /* DAC_MUTE */
+#define WM8400_DAC_MUTE_SHIFT 2 /* DAC_MUTE */
+#define WM8400_DAC_MUTE_WIDTH 1 /* DAC_MUTE */
+#define WM8400_DACL_DATINV 0x0002 /* DACL_DATINV */
+#define WM8400_DACL_DATINV_MASK 0x0002 /* DACL_DATINV */
+#define WM8400_DACL_DATINV_SHIFT 1 /* DACL_DATINV */
+#define WM8400_DACL_DATINV_WIDTH 1 /* DACL_DATINV */
+#define WM8400_DACR_DATINV 0x0001 /* DACR_DATINV */
+#define WM8400_DACR_DATINV_MASK 0x0001 /* DACR_DATINV */
+#define WM8400_DACR_DATINV_SHIFT 0 /* DACR_DATINV */
+#define WM8400_DACR_DATINV_WIDTH 1 /* DACR_DATINV */
+
+/*
+ * R12 (0x0C) - Left DAC Digital Volume
+ */
+#define WM8400_DAC_VU 0x0100 /* DAC_VU */
+#define WM8400_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8400_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_SHIFT 0 /* DACL_VOL - [7:0] */
+#define WM8400_DACL_VOL_WIDTH 8 /* DACL_VOL - [7:0] */
+
+/*
+ * R13 (0x0D) - Right DAC Digital Volume
+ */
+#define WM8400_DAC_VU 0x0100 /* DAC_VU */
+#define WM8400_DAC_VU_MASK 0x0100 /* DAC_VU */
+#define WM8400_DAC_VU_SHIFT 8 /* DAC_VU */
+#define WM8400_DAC_VU_WIDTH 1 /* DAC_VU */
+#define WM8400_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_SHIFT 0 /* DACR_VOL - [7:0] */
+#define WM8400_DACR_VOL_WIDTH 8 /* DACR_VOL - [7:0] */
+
+/*
+ * R14 (0x0E) - Digital Side Tone
+ */
+#define WM8400_ADCL_DAC_SVOL_MASK 0x1E00 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_SHIFT 9 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCL_DAC_SVOL_WIDTH 4 /* ADCL_DAC_SVOL - [12:9] */
+#define WM8400_ADCR_DAC_SVOL_MASK 0x01E0 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_SHIFT 5 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADCR_DAC_SVOL_WIDTH 4 /* ADCR_DAC_SVOL - [8:5] */
+#define WM8400_ADC_TO_DACL_MASK 0x000C /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_SHIFT 2 /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACL_WIDTH 2 /* ADC_TO_DACL - [3:2] */
+#define WM8400_ADC_TO_DACR_MASK 0x0003 /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_SHIFT 0 /* ADC_TO_DACR - [1:0] */
+#define WM8400_ADC_TO_DACR_WIDTH 2 /* ADC_TO_DACR - [1:0] */
+
+/*
+ * R15 (0x0F) - ADC CTRL
+ */
+#define WM8400_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_MASK 0x0100 /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_SHIFT 8 /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_ENA_WIDTH 1 /* ADC_HPF_ENA */
+#define WM8400_ADC_HPF_CUT_MASK 0x0060 /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_SHIFT 5 /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADC_HPF_CUT_WIDTH 2 /* ADC_HPF_CUT - [6:5] */
+#define WM8400_ADCL_DATINV 0x0002 /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_MASK 0x0002 /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_SHIFT 1 /* ADCL_DATINV */
+#define WM8400_ADCL_DATINV_WIDTH 1 /* ADCL_DATINV */
+#define WM8400_ADCR_DATINV 0x0001 /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_MASK 0x0001 /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_SHIFT 0 /* ADCR_DATINV */
+#define WM8400_ADCR_DATINV_WIDTH 1 /* ADCR_DATINV */
+
+/*
+ * R16 (0x10) - Left ADC Digital Volume
+ */
+#define WM8400_ADC_VU 0x0100 /* ADC_VU */
+#define WM8400_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8400_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_SHIFT 0 /* ADCL_VOL - [7:0] */
+#define WM8400_ADCL_VOL_WIDTH 8 /* ADCL_VOL - [7:0] */
+
+/*
+ * R17 (0x11) - Right ADC Digital Volume
+ */
+#define WM8400_ADC_VU 0x0100 /* ADC_VU */
+#define WM8400_ADC_VU_MASK 0x0100 /* ADC_VU */
+#define WM8400_ADC_VU_SHIFT 8 /* ADC_VU */
+#define WM8400_ADC_VU_WIDTH 1 /* ADC_VU */
+#define WM8400_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_SHIFT 0 /* ADCR_VOL - [7:0] */
+#define WM8400_ADCR_VOL_WIDTH 8 /* ADCR_VOL - [7:0] */
+
+/*
+ * R24 (0x18) - Left Line Input 1&2 Volume
+ */
+#define WM8400_IPVU 0x0100 /* IPVU */
+#define WM8400_IPVU_MASK 0x0100 /* IPVU */
+#define WM8400_IPVU_SHIFT 8 /* IPVU */
+#define WM8400_IPVU_WIDTH 1 /* IPVU */
+#define WM8400_LI12MUTE 0x0080 /* LI12MUTE */
+#define WM8400_LI12MUTE_MASK 0x0080 /* LI12MUTE */
+#define WM8400_LI12MUTE_SHIFT 7 /* LI12MUTE */
+#define WM8400_LI12MUTE_WIDTH 1 /* LI12MUTE */
+#define WM8400_LI12ZC 0x0040 /* LI12ZC */
+#define WM8400_LI12ZC_MASK 0x0040 /* LI12ZC */
+#define WM8400_LI12ZC_SHIFT 6 /* LI12ZC */
+#define WM8400_LI12ZC_WIDTH 1 /* LI12ZC */
+#define WM8400_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_SHIFT 0 /* LIN12VOL - [4:0] */
+#define WM8400_LIN12VOL_WIDTH 5 /* LIN12VOL - [4:0] */
+
+/*
+ * R25 (0x19) - Left Line Input 3&4 Volume
+ */
+#define WM8400_IPVU 0x0100 /* IPVU */
+#define WM8400_IPVU_MASK 0x0100 /* IPVU */
+#define WM8400_IPVU_SHIFT 8 /* IPVU */
+#define WM8400_IPVU_WIDTH 1 /* IPVU */
+#define WM8400_LI34MUTE 0x0080 /* LI34MUTE */
+#define WM8400_LI34MUTE_MASK 0x0080 /* LI34MUTE */
+#define WM8400_LI34MUTE_SHIFT 7 /* LI34MUTE */
+#define WM8400_LI34MUTE_WIDTH 1 /* LI34MUTE */
+#define WM8400_LI34ZC 0x0040 /* LI34ZC */
+#define WM8400_LI34ZC_MASK 0x0040 /* LI34ZC */
+#define WM8400_LI34ZC_SHIFT 6 /* LI34ZC */
+#define WM8400_LI34ZC_WIDTH 1 /* LI34ZC */
+#define WM8400_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_SHIFT 0 /* LIN34VOL - [4:0] */
+#define WM8400_LIN34VOL_WIDTH 5 /* LIN34VOL - [4:0] */
+
+/*
+ * R26 (0x1A) - Right Line Input 1&2 Volume
+ */
+#define WM8400_IPVU 0x0100 /* IPVU */
+#define WM8400_IPVU_MASK 0x0100 /* IPVU */
+#define WM8400_IPVU_SHIFT 8 /* IPVU */
+#define WM8400_IPVU_WIDTH 1 /* IPVU */
+#define WM8400_RI12MUTE 0x0080 /* RI12MUTE */
+#define WM8400_RI12MUTE_MASK 0x0080 /* RI12MUTE */
+#define WM8400_RI12MUTE_SHIFT 7 /* RI12MUTE */
+#define WM8400_RI12MUTE_WIDTH 1 /* RI12MUTE */
+#define WM8400_RI12ZC 0x0040 /* RI12ZC */
+#define WM8400_RI12ZC_MASK 0x0040 /* RI12ZC */
+#define WM8400_RI12ZC_SHIFT 6 /* RI12ZC */
+#define WM8400_RI12ZC_WIDTH 1 /* RI12ZC */
+#define WM8400_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_SHIFT 0 /* RIN12VOL - [4:0] */
+#define WM8400_RIN12VOL_WIDTH 5 /* RIN12VOL - [4:0] */
+
+/*
+ * R27 (0x1B) - Right Line Input 3&4 Volume
+ */
+#define WM8400_IPVU 0x0100 /* IPVU */
+#define WM8400_IPVU_MASK 0x0100 /* IPVU */
+#define WM8400_IPVU_SHIFT 8 /* IPVU */
+#define WM8400_IPVU_WIDTH 1 /* IPVU */
+#define WM8400_RI34MUTE 0x0080 /* RI34MUTE */
+#define WM8400_RI34MUTE_MASK 0x0080 /* RI34MUTE */
+#define WM8400_RI34MUTE_SHIFT 7 /* RI34MUTE */
+#define WM8400_RI34MUTE_WIDTH 1 /* RI34MUTE */
+#define WM8400_RI34ZC 0x0040 /* RI34ZC */
+#define WM8400_RI34ZC_MASK 0x0040 /* RI34ZC */
+#define WM8400_RI34ZC_SHIFT 6 /* RI34ZC */
+#define WM8400_RI34ZC_WIDTH 1 /* RI34ZC */
+#define WM8400_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_SHIFT 0 /* RIN34VOL - [4:0] */
+#define WM8400_RIN34VOL_WIDTH 5 /* RIN34VOL - [4:0] */
+
+/*
+ * R28 (0x1C) - Left Output Volume
+ */
+#define WM8400_OPVU 0x0100 /* OPVU */
+#define WM8400_OPVU_MASK 0x0100 /* OPVU */
+#define WM8400_OPVU_SHIFT 8 /* OPVU */
+#define WM8400_OPVU_WIDTH 1 /* OPVU */
+#define WM8400_LOZC 0x0080 /* LOZC */
+#define WM8400_LOZC_MASK 0x0080 /* LOZC */
+#define WM8400_LOZC_SHIFT 7 /* LOZC */
+#define WM8400_LOZC_WIDTH 1 /* LOZC */
+#define WM8400_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_SHIFT 0 /* LOUTVOL - [6:0] */
+#define WM8400_LOUTVOL_WIDTH 7 /* LOUTVOL - [6:0] */
+
+/*
+ * R29 (0x1D) - Right Output Volume
+ */
+#define WM8400_OPVU 0x0100 /* OPVU */
+#define WM8400_OPVU_MASK 0x0100 /* OPVU */
+#define WM8400_OPVU_SHIFT 8 /* OPVU */
+#define WM8400_OPVU_WIDTH 1 /* OPVU */
+#define WM8400_ROZC 0x0080 /* ROZC */
+#define WM8400_ROZC_MASK 0x0080 /* ROZC */
+#define WM8400_ROZC_SHIFT 7 /* ROZC */
+#define WM8400_ROZC_WIDTH 1 /* ROZC */
+#define WM8400_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_SHIFT 0 /* ROUTVOL - [6:0] */
+#define WM8400_ROUTVOL_WIDTH 7 /* ROUTVOL - [6:0] */
+
+/*
+ * R30 (0x1E) - Line Outputs Volume
+ */
+#define WM8400_LONMUTE 0x0040 /* LONMUTE */
+#define WM8400_LONMUTE_MASK 0x0040 /* LONMUTE */
+#define WM8400_LONMUTE_SHIFT 6 /* LONMUTE */
+#define WM8400_LONMUTE_WIDTH 1 /* LONMUTE */
+#define WM8400_LOPMUTE 0x0020 /* LOPMUTE */
+#define WM8400_LOPMUTE_MASK 0x0020 /* LOPMUTE */
+#define WM8400_LOPMUTE_SHIFT 5 /* LOPMUTE */
+#define WM8400_LOPMUTE_WIDTH 1 /* LOPMUTE */
+#define WM8400_LOATTN 0x0010 /* LOATTN */
+#define WM8400_LOATTN_MASK 0x0010 /* LOATTN */
+#define WM8400_LOATTN_SHIFT 4 /* LOATTN */
+#define WM8400_LOATTN_WIDTH 1 /* LOATTN */
+#define WM8400_RONMUTE 0x0004 /* RONMUTE */
+#define WM8400_RONMUTE_MASK 0x0004 /* RONMUTE */
+#define WM8400_RONMUTE_SHIFT 2 /* RONMUTE */
+#define WM8400_RONMUTE_WIDTH 1 /* RONMUTE */
+#define WM8400_ROPMUTE 0x0002 /* ROPMUTE */
+#define WM8400_ROPMUTE_MASK 0x0002 /* ROPMUTE */
+#define WM8400_ROPMUTE_SHIFT 1 /* ROPMUTE */
+#define WM8400_ROPMUTE_WIDTH 1 /* ROPMUTE */
+#define WM8400_ROATTN 0x0001 /* ROATTN */
+#define WM8400_ROATTN_MASK 0x0001 /* ROATTN */
+#define WM8400_ROATTN_SHIFT 0 /* ROATTN */
+#define WM8400_ROATTN_WIDTH 1 /* ROATTN */
+
+/*
+ * R31 (0x1F) - Out3/4 Volume
+ */
+#define WM8400_OUT3MUTE 0x0020 /* OUT3MUTE */
+#define WM8400_OUT3MUTE_MASK 0x0020 /* OUT3MUTE */
+#define WM8400_OUT3MUTE_SHIFT 5 /* OUT3MUTE */
+#define WM8400_OUT3MUTE_WIDTH 1 /* OUT3MUTE */
+#define WM8400_OUT3ATTN 0x0010 /* OUT3ATTN */
+#define WM8400_OUT3ATTN_MASK 0x0010 /* OUT3ATTN */
+#define WM8400_OUT3ATTN_SHIFT 4 /* OUT3ATTN */
+#define WM8400_OUT3ATTN_WIDTH 1 /* OUT3ATTN */
+#define WM8400_OUT4MUTE 0x0002 /* OUT4MUTE */
+#define WM8400_OUT4MUTE_MASK 0x0002 /* OUT4MUTE */
+#define WM8400_OUT4MUTE_SHIFT 1 /* OUT4MUTE */
+#define WM8400_OUT4MUTE_WIDTH 1 /* OUT4MUTE */
+#define WM8400_OUT4ATTN 0x0001 /* OUT4ATTN */
+#define WM8400_OUT4ATTN_MASK 0x0001 /* OUT4ATTN */
+#define WM8400_OUT4ATTN_SHIFT 0 /* OUT4ATTN */
+#define WM8400_OUT4ATTN_WIDTH 1 /* OUT4ATTN */
+
+/*
+ * R32 (0x20) - Left OPGA Volume
+ */
+#define WM8400_OPVU 0x0100 /* OPVU */
+#define WM8400_OPVU_MASK 0x0100 /* OPVU */
+#define WM8400_OPVU_SHIFT 8 /* OPVU */
+#define WM8400_OPVU_WIDTH 1 /* OPVU */
+#define WM8400_LOPGAZC 0x0080 /* LOPGAZC */
+#define WM8400_LOPGAZC_MASK 0x0080 /* LOPGAZC */
+#define WM8400_LOPGAZC_SHIFT 7 /* LOPGAZC */
+#define WM8400_LOPGAZC_WIDTH 1 /* LOPGAZC */
+#define WM8400_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_SHIFT 0 /* LOPGAVOL - [6:0] */
+#define WM8400_LOPGAVOL_WIDTH 7 /* LOPGAVOL - [6:0] */
+
+/*
+ * R33 (0x21) - Right OPGA Volume
+ */
+#define WM8400_OPVU 0x0100 /* OPVU */
+#define WM8400_OPVU_MASK 0x0100 /* OPVU */
+#define WM8400_OPVU_SHIFT 8 /* OPVU */
+#define WM8400_OPVU_WIDTH 1 /* OPVU */
+#define WM8400_ROPGAZC 0x0080 /* ROPGAZC */
+#define WM8400_ROPGAZC_MASK 0x0080 /* ROPGAZC */
+#define WM8400_ROPGAZC_SHIFT 7 /* ROPGAZC */
+#define WM8400_ROPGAZC_WIDTH 1 /* ROPGAZC */
+#define WM8400_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_SHIFT 0 /* ROPGAVOL - [6:0] */
+#define WM8400_ROPGAVOL_WIDTH 7 /* ROPGAVOL - [6:0] */
+
+/*
+ * R34 (0x22) - Speaker Volume
+ */
+#define WM8400_SPKATTN_MASK 0x0003 /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_SHIFT 0 /* SPKATTN - [1:0] */
+#define WM8400_SPKATTN_WIDTH 2 /* SPKATTN - [1:0] */
+
+/*
+ * R35 (0x23) - ClassD1
+ */
+#define WM8400_CDMODE 0x0100 /* CDMODE */
+#define WM8400_CDMODE_MASK 0x0100 /* CDMODE */
+#define WM8400_CDMODE_SHIFT 8 /* CDMODE */
+#define WM8400_CDMODE_WIDTH 1 /* CDMODE */
+#define WM8400_CLASSD_CLK_SEL 0x0080 /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_MASK 0x0080 /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_SHIFT 7 /* CLASSD_CLK_SEL */
+#define WM8400_CLASSD_CLK_SEL_WIDTH 1 /* CLASSD_CLK_SEL */
+#define WM8400_CD_SRCTRL 0x0040 /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_MASK 0x0040 /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_SHIFT 6 /* CD_SRCTRL */
+#define WM8400_CD_SRCTRL_WIDTH 1 /* CD_SRCTRL */
+#define WM8400_SPKNOPOP 0x0020 /* SPKNOPOP */
+#define WM8400_SPKNOPOP_MASK 0x0020 /* SPKNOPOP */
+#define WM8400_SPKNOPOP_SHIFT 5 /* SPKNOPOP */
+#define WM8400_SPKNOPOP_WIDTH 1 /* SPKNOPOP */
+#define WM8400_DBLERATE 0x0010 /* DBLERATE */
+#define WM8400_DBLERATE_MASK 0x0010 /* DBLERATE */
+#define WM8400_DBLERATE_SHIFT 4 /* DBLERATE */
+#define WM8400_DBLERATE_WIDTH 1 /* DBLERATE */
+#define WM8400_LOOPTEST 0x0008 /* LOOPTEST */
+#define WM8400_LOOPTEST_MASK 0x0008 /* LOOPTEST */
+#define WM8400_LOOPTEST_SHIFT 3 /* LOOPTEST */
+#define WM8400_LOOPTEST_WIDTH 1 /* LOOPTEST */
+#define WM8400_HALFABBIAS 0x0004 /* HALFABBIAS */
+#define WM8400_HALFABBIAS_MASK 0x0004 /* HALFABBIAS */
+#define WM8400_HALFABBIAS_SHIFT 2 /* HALFABBIAS */
+#define WM8400_HALFABBIAS_WIDTH 1 /* HALFABBIAS */
+#define WM8400_TRIDEL_MASK 0x0003 /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_SHIFT 0 /* TRIDEL - [1:0] */
+#define WM8400_TRIDEL_WIDTH 2 /* TRIDEL - [1:0] */
+
+/*
+ * R37 (0x25) - ClassD3
+ */
+#define WM8400_DCGAIN_MASK 0x0038 /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_SHIFT 3 /* DCGAIN - [5:3] */
+#define WM8400_DCGAIN_WIDTH 3 /* DCGAIN - [5:3] */
+#define WM8400_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_SHIFT 0 /* ACGAIN - [2:0] */
+#define WM8400_ACGAIN_WIDTH 3 /* ACGAIN - [2:0] */
+
+/*
+ * R39 (0x27) - Input Mixer1
+ */
+#define WM8400_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_SHIFT 2 /* AINLMODE - [3:2] */
+#define WM8400_AINLMODE_WIDTH 2 /* AINLMODE - [3:2] */
+#define WM8400_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_SHIFT 0 /* AINRMODE - [1:0] */
+#define WM8400_AINRMODE_WIDTH 2 /* AINRMODE - [1:0] */
+
+/*
+ * R40 (0x28) - Input Mixer2
+ */
+#define WM8400_LMP4 0x0080 /* LMP4 */
+#define WM8400_LMP4_MASK 0x0080 /* LMP4 */
+#define WM8400_LMP4_SHIFT 7 /* LMP4 */
+#define WM8400_LMP4_WIDTH 1 /* LMP4 */
+#define WM8400_LMN3 0x0040 /* LMN3 */
+#define WM8400_LMN3_MASK 0x0040 /* LMN3 */
+#define WM8400_LMN3_SHIFT 6 /* LMN3 */
+#define WM8400_LMN3_WIDTH 1 /* LMN3 */
+#define WM8400_LMP2 0x0020 /* LMP2 */
+#define WM8400_LMP2_MASK 0x0020 /* LMP2 */
+#define WM8400_LMP2_SHIFT 5 /* LMP2 */
+#define WM8400_LMP2_WIDTH 1 /* LMP2 */
+#define WM8400_LMN1 0x0010 /* LMN1 */
+#define WM8400_LMN1_MASK 0x0010 /* LMN1 */
+#define WM8400_LMN1_SHIFT 4 /* LMN1 */
+#define WM8400_LMN1_WIDTH 1 /* LMN1 */
+#define WM8400_RMP4 0x0008 /* RMP4 */
+#define WM8400_RMP4_MASK 0x0008 /* RMP4 */
+#define WM8400_RMP4_SHIFT 3 /* RMP4 */
+#define WM8400_RMP4_WIDTH 1 /* RMP4 */
+#define WM8400_RMN3 0x0004 /* RMN3 */
+#define WM8400_RMN3_MASK 0x0004 /* RMN3 */
+#define WM8400_RMN3_SHIFT 2 /* RMN3 */
+#define WM8400_RMN3_WIDTH 1 /* RMN3 */
+#define WM8400_RMP2 0x0002 /* RMP2 */
+#define WM8400_RMP2_MASK 0x0002 /* RMP2 */
+#define WM8400_RMP2_SHIFT 1 /* RMP2 */
+#define WM8400_RMP2_WIDTH 1 /* RMP2 */
+#define WM8400_RMN1 0x0001 /* RMN1 */
+#define WM8400_RMN1_MASK 0x0001 /* RMN1 */
+#define WM8400_RMN1_SHIFT 0 /* RMN1 */
+#define WM8400_RMN1_WIDTH 1 /* RMN1 */
+
+/*
+ * R41 (0x29) - Input Mixer3
+ */
+#define WM8400_L34MNB 0x0100 /* L34MNB */
+#define WM8400_L34MNB_MASK 0x0100 /* L34MNB */
+#define WM8400_L34MNB_SHIFT 8 /* L34MNB */
+#define WM8400_L34MNB_WIDTH 1 /* L34MNB */
+#define WM8400_L34MNBST 0x0080 /* L34MNBST */
+#define WM8400_L34MNBST_MASK 0x0080 /* L34MNBST */
+#define WM8400_L34MNBST_SHIFT 7 /* L34MNBST */
+#define WM8400_L34MNBST_WIDTH 1 /* L34MNBST */
+#define WM8400_L12MNB 0x0020 /* L12MNB */
+#define WM8400_L12MNB_MASK 0x0020 /* L12MNB */
+#define WM8400_L12MNB_SHIFT 5 /* L12MNB */
+#define WM8400_L12MNB_WIDTH 1 /* L12MNB */
+#define WM8400_L12MNBST 0x0010 /* L12MNBST */
+#define WM8400_L12MNBST_MASK 0x0010 /* L12MNBST */
+#define WM8400_L12MNBST_SHIFT 4 /* L12MNBST */
+#define WM8400_L12MNBST_WIDTH 1 /* L12MNBST */
+#define WM8400_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_SHIFT 0 /* LDBVOL - [2:0] */
+#define WM8400_LDBVOL_WIDTH 3 /* LDBVOL - [2:0] */
+
+/*
+ * R42 (0x2A) - Input Mixer4
+ */
+#define WM8400_R34MNB 0x0100 /* R34MNB */
+#define WM8400_R34MNB_MASK 0x0100 /* R34MNB */
+#define WM8400_R34MNB_SHIFT 8 /* R34MNB */
+#define WM8400_R34MNB_WIDTH 1 /* R34MNB */
+#define WM8400_R34MNBST 0x0080 /* R34MNBST */
+#define WM8400_R34MNBST_MASK 0x0080 /* R34MNBST */
+#define WM8400_R34MNBST_SHIFT 7 /* R34MNBST */
+#define WM8400_R34MNBST_WIDTH 1 /* R34MNBST */
+#define WM8400_R12MNB 0x0020 /* R12MNB */
+#define WM8400_R12MNB_MASK 0x0020 /* R12MNB */
+#define WM8400_R12MNB_SHIFT 5 /* R12MNB */
+#define WM8400_R12MNB_WIDTH 1 /* R12MNB */
+#define WM8400_R12MNBST 0x0010 /* R12MNBST */
+#define WM8400_R12MNBST_MASK 0x0010 /* R12MNBST */
+#define WM8400_R12MNBST_SHIFT 4 /* R12MNBST */
+#define WM8400_R12MNBST_WIDTH 1 /* R12MNBST */
+#define WM8400_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_SHIFT 0 /* RDBVOL - [2:0] */
+#define WM8400_RDBVOL_WIDTH 3 /* RDBVOL - [2:0] */
+
+/*
+ * R43 (0x2B) - Input Mixer5
+ */
+#define WM8400_LI2BVOL_MASK 0x01C0 /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_SHIFT 6 /* LI2BVOL - [8:6] */
+#define WM8400_LI2BVOL_WIDTH 3 /* LI2BVOL - [8:6] */
+#define WM8400_LR4BVOL_MASK 0x0038 /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_SHIFT 3 /* LR4BVOL - [5:3] */
+#define WM8400_LR4BVOL_WIDTH 3 /* LR4BVOL - [5:3] */
+#define WM8400_LL4BVOL_MASK 0x0007 /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_SHIFT 0 /* LL4BVOL - [2:0] */
+#define WM8400_LL4BVOL_WIDTH 3 /* LL4BVOL - [2:0] */
+
+/*
+ * R44 (0x2C) - Input Mixer6
+ */
+#define WM8400_RI2BVOL_MASK 0x01C0 /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_SHIFT 6 /* RI2BVOL - [8:6] */
+#define WM8400_RI2BVOL_WIDTH 3 /* RI2BVOL - [8:6] */
+#define WM8400_RL4BVOL_MASK 0x0038 /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_SHIFT 3 /* RL4BVOL - [5:3] */
+#define WM8400_RL4BVOL_WIDTH 3 /* RL4BVOL - [5:3] */
+#define WM8400_RR4BVOL_MASK 0x0007 /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_SHIFT 0 /* RR4BVOL - [2:0] */
+#define WM8400_RR4BVOL_WIDTH 3 /* RR4BVOL - [2:0] */
+
+/*
+ * R45 (0x2D) - Output Mixer1
+ */
+#define WM8400_LRBLO 0x0080 /* LRBLO */
+#define WM8400_LRBLO_MASK 0x0080 /* LRBLO */
+#define WM8400_LRBLO_SHIFT 7 /* LRBLO */
+#define WM8400_LRBLO_WIDTH 1 /* LRBLO */
+#define WM8400_LLBLO 0x0040 /* LLBLO */
+#define WM8400_LLBLO_MASK 0x0040 /* LLBLO */
+#define WM8400_LLBLO_SHIFT 6 /* LLBLO */
+#define WM8400_LLBLO_WIDTH 1 /* LLBLO */
+#define WM8400_LRI3LO 0x0020 /* LRI3LO */
+#define WM8400_LRI3LO_MASK 0x0020 /* LRI3LO */
+#define WM8400_LRI3LO_SHIFT 5 /* LRI3LO */
+#define WM8400_LRI3LO_WIDTH 1 /* LRI3LO */
+#define WM8400_LLI3LO 0x0010 /* LLI3LO */
+#define WM8400_LLI3LO_MASK 0x0010 /* LLI3LO */
+#define WM8400_LLI3LO_SHIFT 4 /* LLI3LO */
+#define WM8400_LLI3LO_WIDTH 1 /* LLI3LO */
+#define WM8400_LR12LO 0x0008 /* LR12LO */
+#define WM8400_LR12LO_MASK 0x0008 /* LR12LO */
+#define WM8400_LR12LO_SHIFT 3 /* LR12LO */
+#define WM8400_LR12LO_WIDTH 1 /* LR12LO */
+#define WM8400_LL12LO 0x0004 /* LL12LO */
+#define WM8400_LL12LO_MASK 0x0004 /* LL12LO */
+#define WM8400_LL12LO_SHIFT 2 /* LL12LO */
+#define WM8400_LL12LO_WIDTH 1 /* LL12LO */
+#define WM8400_LDLO 0x0001 /* LDLO */
+#define WM8400_LDLO_MASK 0x0001 /* LDLO */
+#define WM8400_LDLO_SHIFT 0 /* LDLO */
+#define WM8400_LDLO_WIDTH 1 /* LDLO */
+
+/*
+ * R46 (0x2E) - Output Mixer2
+ */
+#define WM8400_RLBRO 0x0080 /* RLBRO */
+#define WM8400_RLBRO_MASK 0x0080 /* RLBRO */
+#define WM8400_RLBRO_SHIFT 7 /* RLBRO */
+#define WM8400_RLBRO_WIDTH 1 /* RLBRO */
+#define WM8400_RRBRO 0x0040 /* RRBRO */
+#define WM8400_RRBRO_MASK 0x0040 /* RRBRO */
+#define WM8400_RRBRO_SHIFT 6 /* RRBRO */
+#define WM8400_RRBRO_WIDTH 1 /* RRBRO */
+#define WM8400_RLI3RO 0x0020 /* RLI3RO */
+#define WM8400_RLI3RO_MASK 0x0020 /* RLI3RO */
+#define WM8400_RLI3RO_SHIFT 5 /* RLI3RO */
+#define WM8400_RLI3RO_WIDTH 1 /* RLI3RO */
+#define WM8400_RRI3RO 0x0010 /* RRI3RO */
+#define WM8400_RRI3RO_MASK 0x0010 /* RRI3RO */
+#define WM8400_RRI3RO_SHIFT 4 /* RRI3RO */
+#define WM8400_RRI3RO_WIDTH 1 /* RRI3RO */
+#define WM8400_RL12RO 0x0008 /* RL12RO */
+#define WM8400_RL12RO_MASK 0x0008 /* RL12RO */
+#define WM8400_RL12RO_SHIFT 3 /* RL12RO */
+#define WM8400_RL12RO_WIDTH 1 /* RL12RO */
+#define WM8400_RR12RO 0x0004 /* RR12RO */
+#define WM8400_RR12RO_MASK 0x0004 /* RR12RO */
+#define WM8400_RR12RO_SHIFT 2 /* RR12RO */
+#define WM8400_RR12RO_WIDTH 1 /* RR12RO */
+#define WM8400_RDRO 0x0001 /* RDRO */
+#define WM8400_RDRO_MASK 0x0001 /* RDRO */
+#define WM8400_RDRO_SHIFT 0 /* RDRO */
+#define WM8400_RDRO_WIDTH 1 /* RDRO */
+
+/*
+ * R47 (0x2F) - Output Mixer3
+ */
+#define WM8400_LLI3LOVOL_MASK 0x01C0 /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_SHIFT 6 /* LLI3LOVOL - [8:6] */
+#define WM8400_LLI3LOVOL_WIDTH 3 /* LLI3LOVOL - [8:6] */
+#define WM8400_LR12LOVOL_MASK 0x0038 /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_SHIFT 3 /* LR12LOVOL - [5:3] */
+#define WM8400_LR12LOVOL_WIDTH 3 /* LR12LOVOL - [5:3] */
+#define WM8400_LL12LOVOL_MASK 0x0007 /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_SHIFT 0 /* LL12LOVOL - [2:0] */
+#define WM8400_LL12LOVOL_WIDTH 3 /* LL12LOVOL - [2:0] */
+
+/*
+ * R48 (0x30) - Output Mixer4
+ */
+#define WM8400_RRI3ROVOL_MASK 0x01C0 /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_SHIFT 6 /* RRI3ROVOL - [8:6] */
+#define WM8400_RRI3ROVOL_WIDTH 3 /* RRI3ROVOL - [8:6] */
+#define WM8400_RL12ROVOL_MASK 0x0038 /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_SHIFT 3 /* RL12ROVOL - [5:3] */
+#define WM8400_RL12ROVOL_WIDTH 3 /* RL12ROVOL - [5:3] */
+#define WM8400_RR12ROVOL_MASK 0x0007 /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_SHIFT 0 /* RR12ROVOL - [2:0] */
+#define WM8400_RR12ROVOL_WIDTH 3 /* RR12ROVOL - [2:0] */
+
+/*
+ * R49 (0x31) - Output Mixer5
+ */
+#define WM8400_LRI3LOVOL_MASK 0x01C0 /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_SHIFT 6 /* LRI3LOVOL - [8:6] */
+#define WM8400_LRI3LOVOL_WIDTH 3 /* LRI3LOVOL - [8:6] */
+#define WM8400_LRBLOVOL_MASK 0x0038 /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_SHIFT 3 /* LRBLOVOL - [5:3] */
+#define WM8400_LRBLOVOL_WIDTH 3 /* LRBLOVOL - [5:3] */
+#define WM8400_LLBLOVOL_MASK 0x0007 /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_SHIFT 0 /* LLBLOVOL - [2:0] */
+#define WM8400_LLBLOVOL_WIDTH 3 /* LLBLOVOL - [2:0] */
+
+/*
+ * R50 (0x32) - Output Mixer6
+ */
+#define WM8400_RLI3ROVOL_MASK 0x01C0 /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_SHIFT 6 /* RLI3ROVOL - [8:6] */
+#define WM8400_RLI3ROVOL_WIDTH 3 /* RLI3ROVOL - [8:6] */
+#define WM8400_RLBROVOL_MASK 0x0038 /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_SHIFT 3 /* RLBROVOL - [5:3] */
+#define WM8400_RLBROVOL_WIDTH 3 /* RLBROVOL - [5:3] */
+#define WM8400_RRBROVOL_MASK 0x0007 /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_SHIFT 0 /* RRBROVOL - [2:0] */
+#define WM8400_RRBROVOL_WIDTH 3 /* RRBROVOL - [2:0] */
+
+/*
+ * R51 (0x33) - Out3/4 Mixer
+ */
+#define WM8400_VSEL_MASK 0x0180 /* VSEL - [8:7] */
+#define WM8400_VSEL_SHIFT 7 /* VSEL - [8:7] */
+#define WM8400_VSEL_WIDTH 2 /* VSEL - [8:7] */
+#define WM8400_LI4O3 0x0020 /* LI4O3 */
+#define WM8400_LI4O3_MASK 0x0020 /* LI4O3 */
+#define WM8400_LI4O3_SHIFT 5 /* LI4O3 */
+#define WM8400_LI4O3_WIDTH 1 /* LI4O3 */
+#define WM8400_LPGAO3 0x0010 /* LPGAO3 */
+#define WM8400_LPGAO3_MASK 0x0010 /* LPGAO3 */
+#define WM8400_LPGAO3_SHIFT 4 /* LPGAO3 */
+#define WM8400_LPGAO3_WIDTH 1 /* LPGAO3 */
+#define WM8400_RI4O4 0x0002 /* RI4O4 */
+#define WM8400_RI4O4_MASK 0x0002 /* RI4O4 */
+#define WM8400_RI4O4_SHIFT 1 /* RI4O4 */
+#define WM8400_RI4O4_WIDTH 1 /* RI4O4 */
+#define WM8400_RPGAO4 0x0001 /* RPGAO4 */
+#define WM8400_RPGAO4_MASK 0x0001 /* RPGAO4 */
+#define WM8400_RPGAO4_SHIFT 0 /* RPGAO4 */
+#define WM8400_RPGAO4_WIDTH 1 /* RPGAO4 */
+
+/*
+ * R52 (0x34) - Line Mixer1
+ */
+#define WM8400_LLOPGALON 0x0040 /* LLOPGALON */
+#define WM8400_LLOPGALON_MASK 0x0040 /* LLOPGALON */
+#define WM8400_LLOPGALON_SHIFT 6 /* LLOPGALON */
+#define WM8400_LLOPGALON_WIDTH 1 /* LLOPGALON */
+#define WM8400_LROPGALON 0x0020 /* LROPGALON */
+#define WM8400_LROPGALON_MASK 0x0020 /* LROPGALON */
+#define WM8400_LROPGALON_SHIFT 5 /* LROPGALON */
+#define WM8400_LROPGALON_WIDTH 1 /* LROPGALON */
+#define WM8400_LOPLON 0x0010 /* LOPLON */
+#define WM8400_LOPLON_MASK 0x0010 /* LOPLON */
+#define WM8400_LOPLON_SHIFT 4 /* LOPLON */
+#define WM8400_LOPLON_WIDTH 1 /* LOPLON */
+#define WM8400_LR12LOP 0x0004 /* LR12LOP */
+#define WM8400_LR12LOP_MASK 0x0004 /* LR12LOP */
+#define WM8400_LR12LOP_SHIFT 2 /* LR12LOP */
+#define WM8400_LR12LOP_WIDTH 1 /* LR12LOP */
+#define WM8400_LL12LOP 0x0002 /* LL12LOP */
+#define WM8400_LL12LOP_MASK 0x0002 /* LL12LOP */
+#define WM8400_LL12LOP_SHIFT 1 /* LL12LOP */
+#define WM8400_LL12LOP_WIDTH 1 /* LL12LOP */
+#define WM8400_LLOPGALOP 0x0001 /* LLOPGALOP */
+#define WM8400_LLOPGALOP_MASK 0x0001 /* LLOPGALOP */
+#define WM8400_LLOPGALOP_SHIFT 0 /* LLOPGALOP */
+#define WM8400_LLOPGALOP_WIDTH 1 /* LLOPGALOP */
+
+/*
+ * R53 (0x35) - Line Mixer2
+ */
+#define WM8400_RROPGARON 0x0040 /* RROPGARON */
+#define WM8400_RROPGARON_MASK 0x0040 /* RROPGARON */
+#define WM8400_RROPGARON_SHIFT 6 /* RROPGARON */
+#define WM8400_RROPGARON_WIDTH 1 /* RROPGARON */
+#define WM8400_RLOPGARON 0x0020 /* RLOPGARON */
+#define WM8400_RLOPGARON_MASK 0x0020 /* RLOPGARON */
+#define WM8400_RLOPGARON_SHIFT 5 /* RLOPGARON */
+#define WM8400_RLOPGARON_WIDTH 1 /* RLOPGARON */
+#define WM8400_ROPRON 0x0010 /* ROPRON */
+#define WM8400_ROPRON_MASK 0x0010 /* ROPRON */
+#define WM8400_ROPRON_SHIFT 4 /* ROPRON */
+#define WM8400_ROPRON_WIDTH 1 /* ROPRON */
+#define WM8400_RL12ROP 0x0004 /* RL12ROP */
+#define WM8400_RL12ROP_MASK 0x0004 /* RL12ROP */
+#define WM8400_RL12ROP_SHIFT 2 /* RL12ROP */
+#define WM8400_RL12ROP_WIDTH 1 /* RL12ROP */
+#define WM8400_RR12ROP 0x0002 /* RR12ROP */
+#define WM8400_RR12ROP_MASK 0x0002 /* RR12ROP */
+#define WM8400_RR12ROP_SHIFT 1 /* RR12ROP */
+#define WM8400_RR12ROP_WIDTH 1 /* RR12ROP */
+#define WM8400_RROPGAROP 0x0001 /* RROPGAROP */
+#define WM8400_RROPGAROP_MASK 0x0001 /* RROPGAROP */
+#define WM8400_RROPGAROP_SHIFT 0 /* RROPGAROP */
+#define WM8400_RROPGAROP_WIDTH 1 /* RROPGAROP */
+
+/*
+ * R54 (0x36) - Speaker Mixer
+ */
+#define WM8400_LB2SPK 0x0080 /* LB2SPK */
+#define WM8400_LB2SPK_MASK 0x0080 /* LB2SPK */
+#define WM8400_LB2SPK_SHIFT 7 /* LB2SPK */
+#define WM8400_LB2SPK_WIDTH 1 /* LB2SPK */
+#define WM8400_RB2SPK 0x0040 /* RB2SPK */
+#define WM8400_RB2SPK_MASK 0x0040 /* RB2SPK */
+#define WM8400_RB2SPK_SHIFT 6 /* RB2SPK */
+#define WM8400_RB2SPK_WIDTH 1 /* RB2SPK */
+#define WM8400_LI2SPK 0x0020 /* LI2SPK */
+#define WM8400_LI2SPK_MASK 0x0020 /* LI2SPK */
+#define WM8400_LI2SPK_SHIFT 5 /* LI2SPK */
+#define WM8400_LI2SPK_WIDTH 1 /* LI2SPK */
+#define WM8400_RI2SPK 0x0010 /* RI2SPK */
+#define WM8400_RI2SPK_MASK 0x0010 /* RI2SPK */
+#define WM8400_RI2SPK_SHIFT 4 /* RI2SPK */
+#define WM8400_RI2SPK_WIDTH 1 /* RI2SPK */
+#define WM8400_LOPGASPK 0x0008 /* LOPGASPK */
+#define WM8400_LOPGASPK_MASK 0x0008 /* LOPGASPK */
+#define WM8400_LOPGASPK_SHIFT 3 /* LOPGASPK */
+#define WM8400_LOPGASPK_WIDTH 1 /* LOPGASPK */
+#define WM8400_ROPGASPK 0x0004 /* ROPGASPK */
+#define WM8400_ROPGASPK_MASK 0x0004 /* ROPGASPK */
+#define WM8400_ROPGASPK_SHIFT 2 /* ROPGASPK */
+#define WM8400_ROPGASPK_WIDTH 1 /* ROPGASPK */
+#define WM8400_LDSPK 0x0002 /* LDSPK */
+#define WM8400_LDSPK_MASK 0x0002 /* LDSPK */
+#define WM8400_LDSPK_SHIFT 1 /* LDSPK */
+#define WM8400_LDSPK_WIDTH 1 /* LDSPK */
+#define WM8400_RDSPK 0x0001 /* RDSPK */
+#define WM8400_RDSPK_MASK 0x0001 /* RDSPK */
+#define WM8400_RDSPK_SHIFT 0 /* RDSPK */
+#define WM8400_RDSPK_WIDTH 1 /* RDSPK */
+
+/*
+ * R55 (0x37) - Additional Control
+ */
+#define WM8400_VROI 0x0001 /* VROI */
+#define WM8400_VROI_MASK 0x0001 /* VROI */
+#define WM8400_VROI_SHIFT 0 /* VROI */
+#define WM8400_VROI_WIDTH 1 /* VROI */
+
+/*
+ * R56 (0x38) - AntiPOP1
+ */
+#define WM8400_DIS_LLINE 0x0020 /* DIS_LLINE */
+#define WM8400_DIS_LLINE_MASK 0x0020 /* DIS_LLINE */
+#define WM8400_DIS_LLINE_SHIFT 5 /* DIS_LLINE */
+#define WM8400_DIS_LLINE_WIDTH 1 /* DIS_LLINE */
+#define WM8400_DIS_RLINE 0x0010 /* DIS_RLINE */
+#define WM8400_DIS_RLINE_MASK 0x0010 /* DIS_RLINE */
+#define WM8400_DIS_RLINE_SHIFT 4 /* DIS_RLINE */
+#define WM8400_DIS_RLINE_WIDTH 1 /* DIS_RLINE */
+#define WM8400_DIS_OUT3 0x0008 /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_MASK 0x0008 /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_SHIFT 3 /* DIS_OUT3 */
+#define WM8400_DIS_OUT3_WIDTH 1 /* DIS_OUT3 */
+#define WM8400_DIS_OUT4 0x0004 /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_MASK 0x0004 /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_SHIFT 2 /* DIS_OUT4 */
+#define WM8400_DIS_OUT4_WIDTH 1 /* DIS_OUT4 */
+#define WM8400_DIS_LOUT 0x0002 /* DIS_LOUT */
+#define WM8400_DIS_LOUT_MASK 0x0002 /* DIS_LOUT */
+#define WM8400_DIS_LOUT_SHIFT 1 /* DIS_LOUT */
+#define WM8400_DIS_LOUT_WIDTH 1 /* DIS_LOUT */
+#define WM8400_DIS_ROUT 0x0001 /* DIS_ROUT */
+#define WM8400_DIS_ROUT_MASK 0x0001 /* DIS_ROUT */
+#define WM8400_DIS_ROUT_SHIFT 0 /* DIS_ROUT */
+#define WM8400_DIS_ROUT_WIDTH 1 /* DIS_ROUT */
+
+/*
+ * R57 (0x39) - AntiPOP2
+ */
+#define WM8400_SOFTST 0x0040 /* SOFTST */
+#define WM8400_SOFTST_MASK 0x0040 /* SOFTST */
+#define WM8400_SOFTST_SHIFT 6 /* SOFTST */
+#define WM8400_SOFTST_WIDTH 1 /* SOFTST */
+#define WM8400_BUFIOEN 0x0008 /* BUFIOEN */
+#define WM8400_BUFIOEN_MASK 0x0008 /* BUFIOEN */
+#define WM8400_BUFIOEN_SHIFT 3 /* BUFIOEN */
+#define WM8400_BUFIOEN_WIDTH 1 /* BUFIOEN */
+#define WM8400_BUFDCOPEN 0x0004 /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_MASK 0x0004 /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_SHIFT 2 /* BUFDCOPEN */
+#define WM8400_BUFDCOPEN_WIDTH 1 /* BUFDCOPEN */
+#define WM8400_POBCTRL 0x0002 /* POBCTRL */
+#define WM8400_POBCTRL_MASK 0x0002 /* POBCTRL */
+#define WM8400_POBCTRL_SHIFT 1 /* POBCTRL */
+#define WM8400_POBCTRL_WIDTH 1 /* POBCTRL */
+#define WM8400_VMIDTOG 0x0001 /* VMIDTOG */
+#define WM8400_VMIDTOG_MASK 0x0001 /* VMIDTOG */
+#define WM8400_VMIDTOG_SHIFT 0 /* VMIDTOG */
+#define WM8400_VMIDTOG_WIDTH 1 /* VMIDTOG */
+
+/*
+ * R58 (0x3A) - MICBIAS
+ */
+#define WM8400_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_SHIFT 6 /* MCDSCTH - [7:6] */
+#define WM8400_MCDSCTH_WIDTH 2 /* MCDSCTH - [7:6] */
+#define WM8400_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_SHIFT 3 /* MCDTHR - [5:3] */
+#define WM8400_MCDTHR_WIDTH 3 /* MCDTHR - [5:3] */
+#define WM8400_MCD 0x0004 /* MCD */
+#define WM8400_MCD_MASK 0x0004 /* MCD */
+#define WM8400_MCD_SHIFT 2 /* MCD */
+#define WM8400_MCD_WIDTH 1 /* MCD */
+#define WM8400_MBSEL 0x0001 /* MBSEL */
+#define WM8400_MBSEL_MASK 0x0001 /* MBSEL */
+#define WM8400_MBSEL_SHIFT 0 /* MBSEL */
+#define WM8400_MBSEL_WIDTH 1 /* MBSEL */
+
+/*
+ * R60 (0x3C) - FLL Control 1
+ */
+#define WM8400_FLL_REF_FREQ 0x1000 /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_MASK 0x1000 /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_SHIFT 12 /* FLL_REF_FREQ */
+#define WM8400_FLL_REF_FREQ_WIDTH 1 /* FLL_REF_FREQ */
+#define WM8400_FLL_CLK_SRC_MASK 0x0C00 /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_SHIFT 10 /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_CLK_SRC_WIDTH 2 /* FLL_CLK_SRC - [11:10] */
+#define WM8400_FLL_FRAC 0x0200 /* FLL_FRAC */
+#define WM8400_FLL_FRAC_MASK 0x0200 /* FLL_FRAC */
+#define WM8400_FLL_FRAC_SHIFT 9 /* FLL_FRAC */
+#define WM8400_FLL_FRAC_WIDTH 1 /* FLL_FRAC */
+#define WM8400_FLL_OSC_ENA 0x0100 /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_MASK 0x0100 /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_SHIFT 8 /* FLL_OSC_ENA */
+#define WM8400_FLL_OSC_ENA_WIDTH 1 /* FLL_OSC_ENA */
+#define WM8400_FLL_CTRL_RATE_MASK 0x00E0 /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_SHIFT 5 /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_CTRL_RATE_WIDTH 3 /* FLL_CTRL_RATE - [7:5] */
+#define WM8400_FLL_FRATIO_MASK 0x001F /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_SHIFT 0 /* FLL_FRATIO - [4:0] */
+#define WM8400_FLL_FRATIO_WIDTH 5 /* FLL_FRATIO - [4:0] */
+
+/*
+ * R61 (0x3D) - FLL Control 2
+ */
+#define WM8400_FLL_K_MASK 0xFFFF /* FLL_K - [15:0] */
+#define WM8400_FLL_K_SHIFT 0 /* FLL_K - [15:0] */
+#define WM8400_FLL_K_WIDTH 16 /* FLL_K - [15:0] */
+
+/*
+ * R62 (0x3E) - FLL Control 3
+ */
+#define WM8400_FLL_N_MASK 0x03FF /* FLL_N - [9:0] */
+#define WM8400_FLL_N_SHIFT 0 /* FLL_N - [9:0] */
+#define WM8400_FLL_N_WIDTH 10 /* FLL_N - [9:0] */
+
+/*
+ * R63 (0x3F) - FLL Control 4
+ */
+#define WM8400_FLL_TRK_GAIN_MASK 0x0078 /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_SHIFT 3 /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_TRK_GAIN_WIDTH 4 /* FLL_TRK_GAIN - [6:3] */
+#define WM8400_FLL_OUTDIV_MASK 0x0007 /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_SHIFT 0 /* FLL_OUTDIV - [2:0] */
+#define WM8400_FLL_OUTDIV_WIDTH 3 /* FLL_OUTDIV - [2:0] */
+
+void wm8400_reset_codec_reg_cache(struct wm8400 *wm8400);
+
+#endif
diff --git a/include/linux/mfd/wm8400-private.h b/include/linux/mfd/wm8400-private.h
new file mode 100644
index 00000000000..2aab4e93a5c
--- /dev/null
+++ b/include/linux/mfd/wm8400-private.h
@@ -0,0 +1,936 @@
+/*
+ * wm8400 private definitions.
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * 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 __LINUX_MFD_WM8400_PRIV_H
+#define __LINUX_MFD_WM8400_PRIV_H
+
+#include <linux/mfd/wm8400.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+
+#define WM8400_REGISTER_COUNT 0x55
+
+struct wm8400 {
+ struct device *dev;
+
+ int (*read_dev)(void *data, char reg, int count, u16 *dst);
+ int (*write_dev)(void *data, char reg, int count, const u16 *src);
+
+ struct mutex io_lock;
+ void *io_data;
+
+ u16 reg_cache[WM8400_REGISTER_COUNT];
+
+ struct platform_device regulators[6];
+};
+
+/*
+ * Register values.
+ */
+#define WM8400_RESET_ID 0x00
+#define WM8400_ID 0x01
+#define WM8400_POWER_MANAGEMENT_1 0x02
+#define WM8400_POWER_MANAGEMENT_2 0x03
+#define WM8400_POWER_MANAGEMENT_3 0x04
+#define WM8400_AUDIO_INTERFACE_1 0x05
+#define WM8400_AUDIO_INTERFACE_2 0x06
+#define WM8400_CLOCKING_1 0x07
+#define WM8400_CLOCKING_2 0x08
+#define WM8400_AUDIO_INTERFACE_3 0x09
+#define WM8400_AUDIO_INTERFACE_4 0x0A
+#define WM8400_DAC_CTRL 0x0B
+#define WM8400_LEFT_DAC_DIGITAL_VOLUME 0x0C
+#define WM8400_RIGHT_DAC_DIGITAL_VOLUME 0x0D
+#define WM8400_DIGITAL_SIDE_TONE 0x0E
+#define WM8400_ADC_CTRL 0x0F
+#define WM8400_LEFT_ADC_DIGITAL_VOLUME 0x10
+#define WM8400_RIGHT_ADC_DIGITAL_VOLUME 0x11
+#define WM8400_GPIO_CTRL_1 0x12
+#define WM8400_GPIO1_GPIO2 0x13
+#define WM8400_GPIO3_GPIO4 0x14
+#define WM8400_GPIO5_GPIO6 0x15
+#define WM8400_GPIOCTRL_2 0x16
+#define WM8400_GPIO_POL 0x17
+#define WM8400_LEFT_LINE_INPUT_1_2_VOLUME 0x18
+#define WM8400_LEFT_LINE_INPUT_3_4_VOLUME 0x19
+#define WM8400_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
+#define WM8400_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
+#define WM8400_LEFT_OUTPUT_VOLUME 0x1C
+#define WM8400_RIGHT_OUTPUT_VOLUME 0x1D
+#define WM8400_LINE_OUTPUTS_VOLUME 0x1E
+#define WM8400_OUT3_4_VOLUME 0x1F
+#define WM8400_LEFT_OPGA_VOLUME 0x20
+#define WM8400_RIGHT_OPGA_VOLUME 0x21
+#define WM8400_SPEAKER_VOLUME 0x22
+#define WM8400_CLASSD1 0x23
+#define WM8400_CLASSD3 0x25
+#define WM8400_INPUT_MIXER1 0x27
+#define WM8400_INPUT_MIXER2 0x28
+#define WM8400_INPUT_MIXER3 0x29
+#define WM8400_INPUT_MIXER4 0x2A
+#define WM8400_INPUT_MIXER5 0x2B
+#define WM8400_INPUT_MIXER6 0x2C
+#define WM8400_OUTPUT_MIXER1 0x2D
+#define WM8400_OUTPUT_MIXER2 0x2E
+#define WM8400_OUTPUT_MIXER3 0x2F
+#define WM8400_OUTPUT_MIXER4 0x30
+#define WM8400_OUTPUT_MIXER5 0x31
+#define WM8400_OUTPUT_MIXER6 0x32
+#define WM8400_OUT3_4_MIXER 0x33
+#define WM8400_LINE_MIXER1 0x34
+#define WM8400_LINE_MIXER2 0x35
+#define WM8400_SPEAKER_MIXER 0x36
+#define WM8400_ADDITIONAL_CONTROL 0x37
+#define WM8400_ANTIPOP1 0x38
+#define WM8400_ANTIPOP2 0x39
+#define WM8400_MICBIAS 0x3A
+#define WM8400_FLL_CONTROL_1 0x3C
+#define WM8400_FLL_CONTROL_2 0x3D
+#define WM8400_FLL_CONTROL_3 0x3E
+#define WM8400_FLL_CONTROL_4 0x3F
+#define WM8400_LDO1_CONTROL 0x41
+#define WM8400_LDO2_CONTROL 0x42
+#define WM8400_LDO3_CONTROL 0x43
+#define WM8400_LDO4_CONTROL 0x44
+#define WM8400_DCDC1_CONTROL_1 0x46
+#define WM8400_DCDC1_CONTROL_2 0x47
+#define WM8400_DCDC2_CONTROL_1 0x48
+#define WM8400_DCDC2_CONTROL_2 0x49
+#define WM8400_INTERFACE 0x4B
+#define WM8400_PM_GENERAL 0x4C
+#define WM8400_PM_SHUTDOWN_CONTROL 0x4E
+#define WM8400_INTERRUPT_STATUS_1 0x4F
+#define WM8400_INTERRUPT_STATUS_1_MASK 0x50
+#define WM8400_INTERRUPT_LEVELS 0x51
+#define WM8400_SHUTDOWN_REASON 0x52
+#define WM8400_LINE_CIRCUITS 0x54
+
+/*
+ * Field Definitions.
+ */
+
+/*
+ * R0 (0x00) - Reset/ID
+ */
+#define WM8400_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_SHIFT 0 /* SW_RESET/CHIP_ID - [15:0] */
+#define WM8400_SW_RESET_CHIP_ID_WIDTH 16 /* SW_RESET/CHIP_ID - [15:0] */
+
+/*
+ * R1 (0x01) - ID
+ */
+#define WM8400_CHIP_REV_MASK 0x7000 /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_SHIFT 12 /* CHIP_REV - [14:12] */
+#define WM8400_CHIP_REV_WIDTH 3 /* CHIP_REV - [14:12] */
+
+/*
+ * R18 (0x12) - GPIO CTRL 1
+ */
+#define WM8400_IRQ 0x1000 /* IRQ */
+#define WM8400_IRQ_MASK 0x1000 /* IRQ */
+#define WM8400_IRQ_SHIFT 12 /* IRQ */
+#define WM8400_IRQ_WIDTH 1 /* IRQ */
+#define WM8400_TEMPOK 0x0800 /* TEMPOK */
+#define WM8400_TEMPOK_MASK 0x0800 /* TEMPOK */
+#define WM8400_TEMPOK_SHIFT 11 /* TEMPOK */
+#define WM8400_TEMPOK_WIDTH 1 /* TEMPOK */
+#define WM8400_MIC1SHRT 0x0400 /* MIC1SHRT */
+#define WM8400_MIC1SHRT_MASK 0x0400 /* MIC1SHRT */
+#define WM8400_MIC1SHRT_SHIFT 10 /* MIC1SHRT */
+#define WM8400_MIC1SHRT_WIDTH 1 /* MIC1SHRT */
+#define WM8400_MIC1DET 0x0200 /* MIC1DET */
+#define WM8400_MIC1DET_MASK 0x0200 /* MIC1DET */
+#define WM8400_MIC1DET_SHIFT 9 /* MIC1DET */
+#define WM8400_MIC1DET_WIDTH 1 /* MIC1DET */
+#define WM8400_FLL_LCK 0x0100 /* FLL_LCK */
+#define WM8400_FLL_LCK_MASK 0x0100 /* FLL_LCK */
+#define WM8400_FLL_LCK_SHIFT 8 /* FLL_LCK */
+#define WM8400_FLL_LCK_WIDTH 1 /* FLL_LCK */
+#define WM8400_GPIO_STATUS_MASK 0x00FF /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_SHIFT 0 /* GPIO_STATUS - [7:0] */
+#define WM8400_GPIO_STATUS_WIDTH 8 /* GPIO_STATUS - [7:0] */
+
+/*
+ * R19 (0x13) - GPIO1 & GPIO2
+ */
+#define WM8400_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_MASK 0x8000 /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_SHIFT 15 /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_DEB_ENA_WIDTH 1 /* GPIO2_DEB_ENA */
+#define WM8400_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_MASK 0x4000 /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_SHIFT 14 /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_IRQ_ENA_WIDTH 1 /* GPIO2_IRQ_ENA */
+#define WM8400_GPIO2_PU 0x2000 /* GPIO2_PU */
+#define WM8400_GPIO2_PU_MASK 0x2000 /* GPIO2_PU */
+#define WM8400_GPIO2_PU_SHIFT 13 /* GPIO2_PU */
+#define WM8400_GPIO2_PU_WIDTH 1 /* GPIO2_PU */
+#define WM8400_GPIO2_PD 0x1000 /* GPIO2_PD */
+#define WM8400_GPIO2_PD_MASK 0x1000 /* GPIO2_PD */
+#define WM8400_GPIO2_PD_SHIFT 12 /* GPIO2_PD */
+#define WM8400_GPIO2_PD_WIDTH 1 /* GPIO2_PD */
+#define WM8400_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_SHIFT 8 /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO2_SEL_WIDTH 4 /* GPIO2_SEL - [11:8] */
+#define WM8400_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_MASK 0x0080 /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_SHIFT 7 /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_DEB_ENA_WIDTH 1 /* GPIO1_DEB_ENA */
+#define WM8400_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_MASK 0x0040 /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_SHIFT 6 /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_IRQ_ENA_WIDTH 1 /* GPIO1_IRQ_ENA */
+#define WM8400_GPIO1_PU 0x0020 /* GPIO1_PU */
+#define WM8400_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */
+#define WM8400_GPIO1_PU_SHIFT 5 /* GPIO1_PU */
+#define WM8400_GPIO1_PU_WIDTH 1 /* GPIO1_PU */
+#define WM8400_GPIO1_PD 0x0010 /* GPIO1_PD */
+#define WM8400_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */
+#define WM8400_GPIO1_PD_SHIFT 4 /* GPIO1_PD */
+#define WM8400_GPIO1_PD_WIDTH 1 /* GPIO1_PD */
+#define WM8400_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */
+#define WM8400_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */
+
+/*
+ * R20 (0x14) - GPIO3 & GPIO4
+ */
+#define WM8400_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_MASK 0x8000 /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_SHIFT 15 /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_DEB_ENA_WIDTH 1 /* GPIO4_DEB_ENA */
+#define WM8400_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_MASK 0x4000 /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_SHIFT 14 /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_IRQ_ENA_WIDTH 1 /* GPIO4_IRQ_ENA */
+#define WM8400_GPIO4_PU 0x2000 /* GPIO4_PU */
+#define WM8400_GPIO4_PU_MASK 0x2000 /* GPIO4_PU */
+#define WM8400_GPIO4_PU_SHIFT 13 /* GPIO4_PU */
+#define WM8400_GPIO4_PU_WIDTH 1 /* GPIO4_PU */
+#define WM8400_GPIO4_PD 0x1000 /* GPIO4_PD */
+#define WM8400_GPIO4_PD_MASK 0x1000 /* GPIO4_PD */
+#define WM8400_GPIO4_PD_SHIFT 12 /* GPIO4_PD */
+#define WM8400_GPIO4_PD_WIDTH 1 /* GPIO4_PD */
+#define WM8400_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_SHIFT 8 /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO4_SEL_WIDTH 4 /* GPIO4_SEL - [11:8] */
+#define WM8400_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_MASK 0x0080 /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_SHIFT 7 /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_DEB_ENA_WIDTH 1 /* GPIO3_DEB_ENA */
+#define WM8400_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_MASK 0x0040 /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_SHIFT 6 /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_IRQ_ENA_WIDTH 1 /* GPIO3_IRQ_ENA */
+#define WM8400_GPIO3_PU 0x0020 /* GPIO3_PU */
+#define WM8400_GPIO3_PU_MASK 0x0020 /* GPIO3_PU */
+#define WM8400_GPIO3_PU_SHIFT 5 /* GPIO3_PU */
+#define WM8400_GPIO3_PU_WIDTH 1 /* GPIO3_PU */
+#define WM8400_GPIO3_PD 0x0010 /* GPIO3_PD */
+#define WM8400_GPIO3_PD_MASK 0x0010 /* GPIO3_PD */
+#define WM8400_GPIO3_PD_SHIFT 4 /* GPIO3_PD */
+#define WM8400_GPIO3_PD_WIDTH 1 /* GPIO3_PD */
+#define WM8400_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_SHIFT 0 /* GPIO3_SEL - [3:0] */
+#define WM8400_GPIO3_SEL_WIDTH 4 /* GPIO3_SEL - [3:0] */
+
+/*
+ * R21 (0x15) - GPIO5 & GPIO6
+ */
+#define WM8400_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_MASK 0x8000 /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_SHIFT 15 /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_DEB_ENA_WIDTH 1 /* GPIO6_DEB_ENA */
+#define WM8400_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_MASK 0x4000 /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_SHIFT 14 /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_IRQ_ENA_WIDTH 1 /* GPIO6_IRQ_ENA */
+#define WM8400_GPIO6_PU 0x2000 /* GPIO6_PU */
+#define WM8400_GPIO6_PU_MASK 0x2000 /* GPIO6_PU */
+#define WM8400_GPIO6_PU_SHIFT 13 /* GPIO6_PU */
+#define WM8400_GPIO6_PU_WIDTH 1 /* GPIO6_PU */
+#define WM8400_GPIO6_PD 0x1000 /* GPIO6_PD */
+#define WM8400_GPIO6_PD_MASK 0x1000 /* GPIO6_PD */
+#define WM8400_GPIO6_PD_SHIFT 12 /* GPIO6_PD */
+#define WM8400_GPIO6_PD_WIDTH 1 /* GPIO6_PD */
+#define WM8400_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_SHIFT 8 /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO6_SEL_WIDTH 4 /* GPIO6_SEL - [11:8] */
+#define WM8400_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_MASK 0x0080 /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_SHIFT 7 /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_DEB_ENA_WIDTH 1 /* GPIO5_DEB_ENA */
+#define WM8400_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_MASK 0x0040 /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_SHIFT 6 /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_IRQ_ENA_WIDTH 1 /* GPIO5_IRQ_ENA */
+#define WM8400_GPIO5_PU 0x0020 /* GPIO5_PU */
+#define WM8400_GPIO5_PU_MASK 0x0020 /* GPIO5_PU */
+#define WM8400_GPIO5_PU_SHIFT 5 /* GPIO5_PU */
+#define WM8400_GPIO5_PU_WIDTH 1 /* GPIO5_PU */
+#define WM8400_GPIO5_PD 0x0010 /* GPIO5_PD */
+#define WM8400_GPIO5_PD_MASK 0x0010 /* GPIO5_PD */
+#define WM8400_GPIO5_PD_SHIFT 4 /* GPIO5_PD */
+#define WM8400_GPIO5_PD_WIDTH 1 /* GPIO5_PD */
+#define WM8400_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_SHIFT 0 /* GPIO5_SEL - [3:0] */
+#define WM8400_GPIO5_SEL_WIDTH 4 /* GPIO5_SEL - [3:0] */
+
+/*
+ * R22 (0x16) - GPIOCTRL 2
+ */
+#define WM8400_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_MASK 0x0800 /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_SHIFT 11 /* TEMPOK_IRQ_ENA */
+#define WM8400_TEMPOK_IRQ_ENA_WIDTH 1 /* TEMPOK_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA 0x0400 /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_MASK 0x0400 /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_SHIFT 10 /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1SHRT_IRQ_ENA_WIDTH 1 /* MIC1SHRT_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA 0x0200 /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_MASK 0x0200 /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_SHIFT 9 /* MIC1DET_IRQ_ENA */
+#define WM8400_MIC1DET_IRQ_ENA_WIDTH 1 /* MIC1DET_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA 0x0100 /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_MASK 0x0100 /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_SHIFT 8 /* FLL_LCK_IRQ_ENA */
+#define WM8400_FLL_LCK_IRQ_ENA_WIDTH 1 /* FLL_LCK_IRQ_ENA */
+#define WM8400_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_MASK 0x0080 /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_SHIFT 7 /* GPI8_DEB_ENA */
+#define WM8400_GPI8_DEB_ENA_WIDTH 1 /* GPI8_DEB_ENA */
+#define WM8400_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_MASK 0x0040 /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_SHIFT 6 /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_IRQ_ENA_WIDTH 1 /* GPI8_IRQ_ENA */
+#define WM8400_GPI8_ENA 0x0010 /* GPI8_ENA */
+#define WM8400_GPI8_ENA_MASK 0x0010 /* GPI8_ENA */
+#define WM8400_GPI8_ENA_SHIFT 4 /* GPI8_ENA */
+#define WM8400_GPI8_ENA_WIDTH 1 /* GPI8_ENA */
+#define WM8400_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_MASK 0x0008 /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_SHIFT 3 /* GPI7_DEB_ENA */
+#define WM8400_GPI7_DEB_ENA_WIDTH 1 /* GPI7_DEB_ENA */
+#define WM8400_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_MASK 0x0004 /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_SHIFT 2 /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_IRQ_ENA_WIDTH 1 /* GPI7_IRQ_ENA */
+#define WM8400_GPI7_ENA 0x0001 /* GPI7_ENA */
+#define WM8400_GPI7_ENA_MASK 0x0001 /* GPI7_ENA */
+#define WM8400_GPI7_ENA_SHIFT 0 /* GPI7_ENA */
+#define WM8400_GPI7_ENA_WIDTH 1 /* GPI7_ENA */
+
+/*
+ * R23 (0x17) - GPIO_POL
+ */
+#define WM8400_IRQ_INV 0x1000 /* IRQ_INV */
+#define WM8400_IRQ_INV_MASK 0x1000 /* IRQ_INV */
+#define WM8400_IRQ_INV_SHIFT 12 /* IRQ_INV */
+#define WM8400_IRQ_INV_WIDTH 1 /* IRQ_INV */
+#define WM8400_TEMPOK_POL 0x0800 /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_MASK 0x0800 /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_SHIFT 11 /* TEMPOK_POL */
+#define WM8400_TEMPOK_POL_WIDTH 1 /* TEMPOK_POL */
+#define WM8400_MIC1SHRT_POL 0x0400 /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_MASK 0x0400 /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_SHIFT 10 /* MIC1SHRT_POL */
+#define WM8400_MIC1SHRT_POL_WIDTH 1 /* MIC1SHRT_POL */
+#define WM8400_MIC1DET_POL 0x0200 /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_MASK 0x0200 /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_SHIFT 9 /* MIC1DET_POL */
+#define WM8400_MIC1DET_POL_WIDTH 1 /* MIC1DET_POL */
+#define WM8400_FLL_LCK_POL 0x0100 /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_MASK 0x0100 /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_SHIFT 8 /* FLL_LCK_POL */
+#define WM8400_FLL_LCK_POL_WIDTH 1 /* FLL_LCK_POL */
+#define WM8400_GPIO_POL_MASK 0x00FF /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_SHIFT 0 /* GPIO_POL - [7:0] */
+#define WM8400_GPIO_POL_WIDTH 8 /* GPIO_POL - [7:0] */
+
+/*
+ * R65 (0x41) - LDO 1 Control
+ */
+#define WM8400_LDO1_ENA 0x8000 /* LDO1_ENA */
+#define WM8400_LDO1_ENA_MASK 0x8000 /* LDO1_ENA */
+#define WM8400_LDO1_ENA_SHIFT 15 /* LDO1_ENA */
+#define WM8400_LDO1_ENA_WIDTH 1 /* LDO1_ENA */
+#define WM8400_LDO1_SWI 0x4000 /* LDO1_SWI */
+#define WM8400_LDO1_SWI_MASK 0x4000 /* LDO1_SWI */
+#define WM8400_LDO1_SWI_SHIFT 14 /* LDO1_SWI */
+#define WM8400_LDO1_SWI_WIDTH 1 /* LDO1_SWI */
+#define WM8400_LDO1_OPFLT 0x1000 /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_MASK 0x1000 /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_SHIFT 12 /* LDO1_OPFLT */
+#define WM8400_LDO1_OPFLT_WIDTH 1 /* LDO1_OPFLT */
+#define WM8400_LDO1_ERRACT 0x0800 /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_MASK 0x0800 /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_SHIFT 11 /* LDO1_ERRACT */
+#define WM8400_LDO1_ERRACT_WIDTH 1 /* LDO1_ERRACT */
+#define WM8400_LDO1_HIB_MODE 0x0400 /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_MASK 0x0400 /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_SHIFT 10 /* LDO1_HIB_MODE */
+#define WM8400_LDO1_HIB_MODE_WIDTH 1 /* LDO1_HIB_MODE */
+#define WM8400_LDO1_VIMG_MASK 0x03E0 /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_SHIFT 5 /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VIMG_WIDTH 5 /* LDO1_VIMG - [9:5] */
+#define WM8400_LDO1_VSEL_MASK 0x001F /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_SHIFT 0 /* LDO1_VSEL - [4:0] */
+#define WM8400_LDO1_VSEL_WIDTH 5 /* LDO1_VSEL - [4:0] */
+
+/*
+ * R66 (0x42) - LDO 2 Control
+ */
+#define WM8400_LDO2_ENA 0x8000 /* LDO2_ENA */
+#define WM8400_LDO2_ENA_MASK 0x8000 /* LDO2_ENA */
+#define WM8400_LDO2_ENA_SHIFT 15 /* LDO2_ENA */
+#define WM8400_LDO2_ENA_WIDTH 1 /* LDO2_ENA */
+#define WM8400_LDO2_SWI 0x4000 /* LDO2_SWI */
+#define WM8400_LDO2_SWI_MASK 0x4000 /* LDO2_SWI */
+#define WM8400_LDO2_SWI_SHIFT 14 /* LDO2_SWI */
+#define WM8400_LDO2_SWI_WIDTH 1 /* LDO2_SWI */
+#define WM8400_LDO2_OPFLT 0x1000 /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_MASK 0x1000 /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_SHIFT 12 /* LDO2_OPFLT */
+#define WM8400_LDO2_OPFLT_WIDTH 1 /* LDO2_OPFLT */
+#define WM8400_LDO2_ERRACT 0x0800 /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_MASK 0x0800 /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_SHIFT 11 /* LDO2_ERRACT */
+#define WM8400_LDO2_ERRACT_WIDTH 1 /* LDO2_ERRACT */
+#define WM8400_LDO2_HIB_MODE 0x0400 /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_MASK 0x0400 /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_SHIFT 10 /* LDO2_HIB_MODE */
+#define WM8400_LDO2_HIB_MODE_WIDTH 1 /* LDO2_HIB_MODE */
+#define WM8400_LDO2_VIMG_MASK 0x03E0 /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_SHIFT 5 /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VIMG_WIDTH 5 /* LDO2_VIMG - [9:5] */
+#define WM8400_LDO2_VSEL_MASK 0x001F /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_SHIFT 0 /* LDO2_VSEL - [4:0] */
+#define WM8400_LDO2_VSEL_WIDTH 5 /* LDO2_VSEL - [4:0] */
+
+/*
+ * R67 (0x43) - LDO 3 Control
+ */
+#define WM8400_LDO3_ENA 0x8000 /* LDO3_ENA */
+#define WM8400_LDO3_ENA_MASK 0x8000 /* LDO3_ENA */
+#define WM8400_LDO3_ENA_SHIFT 15 /* LDO3_ENA */
+#define WM8400_LDO3_ENA_WIDTH 1 /* LDO3_ENA */
+#define WM8400_LDO3_SWI 0x4000 /* LDO3_SWI */
+#define WM8400_LDO3_SWI_MASK 0x4000 /* LDO3_SWI */
+#define WM8400_LDO3_SWI_SHIFT 14 /* LDO3_SWI */
+#define WM8400_LDO3_SWI_WIDTH 1 /* LDO3_SWI */
+#define WM8400_LDO3_OPFLT 0x1000 /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_MASK 0x1000 /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_SHIFT 12 /* LDO3_OPFLT */
+#define WM8400_LDO3_OPFLT_WIDTH 1 /* LDO3_OPFLT */
+#define WM8400_LDO3_ERRACT 0x0800 /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_MASK 0x0800 /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_SHIFT 11 /* LDO3_ERRACT */
+#define WM8400_LDO3_ERRACT_WIDTH 1 /* LDO3_ERRACT */
+#define WM8400_LDO3_HIB_MODE 0x0400 /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_MASK 0x0400 /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_SHIFT 10 /* LDO3_HIB_MODE */
+#define WM8400_LDO3_HIB_MODE_WIDTH 1 /* LDO3_HIB_MODE */
+#define WM8400_LDO3_VIMG_MASK 0x03E0 /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_SHIFT 5 /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VIMG_WIDTH 5 /* LDO3_VIMG - [9:5] */
+#define WM8400_LDO3_VSEL_MASK 0x001F /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_SHIFT 0 /* LDO3_VSEL - [4:0] */
+#define WM8400_LDO3_VSEL_WIDTH 5 /* LDO3_VSEL - [4:0] */
+
+/*
+ * R68 (0x44) - LDO 4 Control
+ */
+#define WM8400_LDO4_ENA 0x8000 /* LDO4_ENA */
+#define WM8400_LDO4_ENA_MASK 0x8000 /* LDO4_ENA */
+#define WM8400_LDO4_ENA_SHIFT 15 /* LDO4_ENA */
+#define WM8400_LDO4_ENA_WIDTH 1 /* LDO4_ENA */
+#define WM8400_LDO4_SWI 0x4000 /* LDO4_SWI */
+#define WM8400_LDO4_SWI_MASK 0x4000 /* LDO4_SWI */
+#define WM8400_LDO4_SWI_SHIFT 14 /* LDO4_SWI */
+#define WM8400_LDO4_SWI_WIDTH 1 /* LDO4_SWI */
+#define WM8400_LDO4_OPFLT 0x1000 /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_MASK 0x1000 /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_SHIFT 12 /* LDO4_OPFLT */
+#define WM8400_LDO4_OPFLT_WIDTH 1 /* LDO4_OPFLT */
+#define WM8400_LDO4_ERRACT 0x0800 /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_MASK 0x0800 /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_SHIFT 11 /* LDO4_ERRACT */
+#define WM8400_LDO4_ERRACT_WIDTH 1 /* LDO4_ERRACT */
+#define WM8400_LDO4_HIB_MODE 0x0400 /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_MASK 0x0400 /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_SHIFT 10 /* LDO4_HIB_MODE */
+#define WM8400_LDO4_HIB_MODE_WIDTH 1 /* LDO4_HIB_MODE */
+#define WM8400_LDO4_VIMG_MASK 0x03E0 /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_SHIFT 5 /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VIMG_WIDTH 5 /* LDO4_VIMG - [9:5] */
+#define WM8400_LDO4_VSEL_MASK 0x001F /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_SHIFT 0 /* LDO4_VSEL - [4:0] */
+#define WM8400_LDO4_VSEL_WIDTH 5 /* LDO4_VSEL - [4:0] */
+
+/*
+ * R70 (0x46) - DCDC1 Control 1
+ */
+#define WM8400_DC1_ENA 0x8000 /* DC1_ENA */
+#define WM8400_DC1_ENA_MASK 0x8000 /* DC1_ENA */
+#define WM8400_DC1_ENA_SHIFT 15 /* DC1_ENA */
+#define WM8400_DC1_ENA_WIDTH 1 /* DC1_ENA */
+#define WM8400_DC1_ACTIVE 0x4000 /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_MASK 0x4000 /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_SHIFT 14 /* DC1_ACTIVE */
+#define WM8400_DC1_ACTIVE_WIDTH 1 /* DC1_ACTIVE */
+#define WM8400_DC1_SLEEP 0x2000 /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_MASK 0x2000 /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_SHIFT 13 /* DC1_SLEEP */
+#define WM8400_DC1_SLEEP_WIDTH 1 /* DC1_SLEEP */
+#define WM8400_DC1_OPFLT 0x1000 /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_MASK 0x1000 /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_SHIFT 12 /* DC1_OPFLT */
+#define WM8400_DC1_OPFLT_WIDTH 1 /* DC1_OPFLT */
+#define WM8400_DC1_ERRACT 0x0800 /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_MASK 0x0800 /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_SHIFT 11 /* DC1_ERRACT */
+#define WM8400_DC1_ERRACT_WIDTH 1 /* DC1_ERRACT */
+#define WM8400_DC1_HIB_MODE 0x0400 /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_MASK 0x0400 /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_SHIFT 10 /* DC1_HIB_MODE */
+#define WM8400_DC1_HIB_MODE_WIDTH 1 /* DC1_HIB_MODE */
+#define WM8400_DC1_SOFTST_MASK 0x0300 /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_SHIFT 8 /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_SOFTST_WIDTH 2 /* DC1_SOFTST - [9:8] */
+#define WM8400_DC1_OV_PROT 0x0080 /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_MASK 0x0080 /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_SHIFT 7 /* DC1_OV_PROT */
+#define WM8400_DC1_OV_PROT_WIDTH 1 /* DC1_OV_PROT */
+#define WM8400_DC1_VSEL_MASK 0x007F /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_SHIFT 0 /* DC1_VSEL - [6:0] */
+#define WM8400_DC1_VSEL_WIDTH 7 /* DC1_VSEL - [6:0] */
+
+/*
+ * R71 (0x47) - DCDC1 Control 2
+ */
+#define WM8400_DC1_FRC_PWM 0x2000 /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_MASK 0x2000 /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_SHIFT 13 /* DC1_FRC_PWM */
+#define WM8400_DC1_FRC_PWM_WIDTH 1 /* DC1_FRC_PWM */
+#define WM8400_DC1_STBY_LIM_MASK 0x0300 /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_SHIFT 8 /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_STBY_LIM_WIDTH 2 /* DC1_STBY_LIM - [9:8] */
+#define WM8400_DC1_ACT_LIM 0x0080 /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_MASK 0x0080 /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_SHIFT 7 /* DC1_ACT_LIM */
+#define WM8400_DC1_ACT_LIM_WIDTH 1 /* DC1_ACT_LIM */
+#define WM8400_DC1_VIMG_MASK 0x007F /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_SHIFT 0 /* DC1_VIMG - [6:0] */
+#define WM8400_DC1_VIMG_WIDTH 7 /* DC1_VIMG - [6:0] */
+
+/*
+ * R72 (0x48) - DCDC2 Control 1
+ */
+#define WM8400_DC2_ENA 0x8000 /* DC2_ENA */
+#define WM8400_DC2_ENA_MASK 0x8000 /* DC2_ENA */
+#define WM8400_DC2_ENA_SHIFT 15 /* DC2_ENA */
+#define WM8400_DC2_ENA_WIDTH 1 /* DC2_ENA */
+#define WM8400_DC2_ACTIVE 0x4000 /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_MASK 0x4000 /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_SHIFT 14 /* DC2_ACTIVE */
+#define WM8400_DC2_ACTIVE_WIDTH 1 /* DC2_ACTIVE */
+#define WM8400_DC2_SLEEP 0x2000 /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_MASK 0x2000 /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_SHIFT 13 /* DC2_SLEEP */
+#define WM8400_DC2_SLEEP_WIDTH 1 /* DC2_SLEEP */
+#define WM8400_DC2_OPFLT 0x1000 /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_MASK 0x1000 /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_SHIFT 12 /* DC2_OPFLT */
+#define WM8400_DC2_OPFLT_WIDTH 1 /* DC2_OPFLT */
+#define WM8400_DC2_ERRACT 0x0800 /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_MASK 0x0800 /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_SHIFT 11 /* DC2_ERRACT */
+#define WM8400_DC2_ERRACT_WIDTH 1 /* DC2_ERRACT */
+#define WM8400_DC2_HIB_MODE 0x0400 /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_MASK 0x0400 /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_SHIFT 10 /* DC2_HIB_MODE */
+#define WM8400_DC2_HIB_MODE_WIDTH 1 /* DC2_HIB_MODE */
+#define WM8400_DC2_SOFTST_MASK 0x0300 /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_SHIFT 8 /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_SOFTST_WIDTH 2 /* DC2_SOFTST - [9:8] */
+#define WM8400_DC2_OV_PROT 0x0080 /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_MASK 0x0080 /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_SHIFT 7 /* DC2_OV_PROT */
+#define WM8400_DC2_OV_PROT_WIDTH 1 /* DC2_OV_PROT */
+#define WM8400_DC2_VSEL_MASK 0x007F /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_SHIFT 0 /* DC2_VSEL - [6:0] */
+#define WM8400_DC2_VSEL_WIDTH 7 /* DC2_VSEL - [6:0] */
+
+/*
+ * R73 (0x49) - DCDC2 Control 2
+ */
+#define WM8400_DC2_FRC_PWM 0x2000 /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_MASK 0x2000 /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_SHIFT 13 /* DC2_FRC_PWM */
+#define WM8400_DC2_FRC_PWM_WIDTH 1 /* DC2_FRC_PWM */
+#define WM8400_DC2_STBY_LIM_MASK 0x0300 /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_SHIFT 8 /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_STBY_LIM_WIDTH 2 /* DC2_STBY_LIM - [9:8] */
+#define WM8400_DC2_ACT_LIM 0x0080 /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_MASK 0x0080 /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_SHIFT 7 /* DC2_ACT_LIM */
+#define WM8400_DC2_ACT_LIM_WIDTH 1 /* DC2_ACT_LIM */
+#define WM8400_DC2_VIMG_MASK 0x007F /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_SHIFT 0 /* DC2_VIMG - [6:0] */
+#define WM8400_DC2_VIMG_WIDTH 7 /* DC2_VIMG - [6:0] */
+
+/*
+ * R75 (0x4B) - Interface
+ */
+#define WM8400_AUTOINC 0x0008 /* AUTOINC */
+#define WM8400_AUTOINC_MASK 0x0008 /* AUTOINC */
+#define WM8400_AUTOINC_SHIFT 3 /* AUTOINC */
+#define WM8400_AUTOINC_WIDTH 1 /* AUTOINC */
+#define WM8400_ARA_ENA 0x0004 /* ARA_ENA */
+#define WM8400_ARA_ENA_MASK 0x0004 /* ARA_ENA */
+#define WM8400_ARA_ENA_SHIFT 2 /* ARA_ENA */
+#define WM8400_ARA_ENA_WIDTH 1 /* ARA_ENA */
+#define WM8400_SPI_CFG 0x0002 /* SPI_CFG */
+#define WM8400_SPI_CFG_MASK 0x0002 /* SPI_CFG */
+#define WM8400_SPI_CFG_SHIFT 1 /* SPI_CFG */
+#define WM8400_SPI_CFG_WIDTH 1 /* SPI_CFG */
+
+/*
+ * R76 (0x4C) - PM GENERAL
+ */
+#define WM8400_CODEC_SOFTST 0x8000 /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_MASK 0x8000 /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_SHIFT 15 /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTST_WIDTH 1 /* CODEC_SOFTST */
+#define WM8400_CODEC_SOFTSD 0x4000 /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_MASK 0x4000 /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_SHIFT 14 /* CODEC_SOFTSD */
+#define WM8400_CODEC_SOFTSD_WIDTH 1 /* CODEC_SOFTSD */
+#define WM8400_CHIP_SOFTSD 0x2000 /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_MASK 0x2000 /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_SHIFT 13 /* CHIP_SOFTSD */
+#define WM8400_CHIP_SOFTSD_WIDTH 1 /* CHIP_SOFTSD */
+#define WM8400_DSLEEP1_POL 0x0008 /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_MASK 0x0008 /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_SHIFT 3 /* DSLEEP1_POL */
+#define WM8400_DSLEEP1_POL_WIDTH 1 /* DSLEEP1_POL */
+#define WM8400_DSLEEP2_POL 0x0004 /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_MASK 0x0004 /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_SHIFT 2 /* DSLEEP2_POL */
+#define WM8400_DSLEEP2_POL_WIDTH 1 /* DSLEEP2_POL */
+#define WM8400_PWR_STATE_MASK 0x0003 /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_SHIFT 0 /* PWR_STATE - [1:0] */
+#define WM8400_PWR_STATE_WIDTH 2 /* PWR_STATE - [1:0] */
+
+/*
+ * R78 (0x4E) - PM Shutdown Control
+ */
+#define WM8400_CHIP_GT150_ERRACT 0x0200 /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_MASK 0x0200 /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_SHIFT 9 /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT150_ERRACT_WIDTH 1 /* CHIP_GT150_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT 0x0100 /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_MASK 0x0100 /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_SHIFT 8 /* CHIP_GT115_ERRACT */
+#define WM8400_CHIP_GT115_ERRACT_WIDTH 1 /* CHIP_GT115_ERRACT */
+#define WM8400_LINE_CMP_ERRACT 0x0080 /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_MASK 0x0080 /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_SHIFT 7 /* LINE_CMP_ERRACT */
+#define WM8400_LINE_CMP_ERRACT_WIDTH 1 /* LINE_CMP_ERRACT */
+#define WM8400_UVLO_ERRACT 0x0040 /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_MASK 0x0040 /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_SHIFT 6 /* UVLO_ERRACT */
+#define WM8400_UVLO_ERRACT_WIDTH 1 /* UVLO_ERRACT */
+
+/*
+ * R79 (0x4F) - Interrupt Status 1
+ */
+#define WM8400_MICD_CINT 0x8000 /* MICD_CINT */
+#define WM8400_MICD_CINT_MASK 0x8000 /* MICD_CINT */
+#define WM8400_MICD_CINT_SHIFT 15 /* MICD_CINT */
+#define WM8400_MICD_CINT_WIDTH 1 /* MICD_CINT */
+#define WM8400_MICSCD_CINT 0x4000 /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_MASK 0x4000 /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_SHIFT 14 /* MICSCD_CINT */
+#define WM8400_MICSCD_CINT_WIDTH 1 /* MICSCD_CINT */
+#define WM8400_JDL_CINT 0x2000 /* JDL_CINT */
+#define WM8400_JDL_CINT_MASK 0x2000 /* JDL_CINT */
+#define WM8400_JDL_CINT_SHIFT 13 /* JDL_CINT */
+#define WM8400_JDL_CINT_WIDTH 1 /* JDL_CINT */
+#define WM8400_JDR_CINT 0x1000 /* JDR_CINT */
+#define WM8400_JDR_CINT_MASK 0x1000 /* JDR_CINT */
+#define WM8400_JDR_CINT_SHIFT 12 /* JDR_CINT */
+#define WM8400_JDR_CINT_WIDTH 1 /* JDR_CINT */
+#define WM8400_CODEC_SEQ_END_EINT 0x0800 /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_MASK 0x0800 /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_SHIFT 11 /* CODEC_SEQ_END_EINT */
+#define WM8400_CODEC_SEQ_END_EINT_WIDTH 1 /* CODEC_SEQ_END_EINT */
+#define WM8400_CDEL_TO_EINT 0x0400 /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_MASK 0x0400 /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_SHIFT 10 /* CDEL_TO_EINT */
+#define WM8400_CDEL_TO_EINT_WIDTH 1 /* CDEL_TO_EINT */
+#define WM8400_CHIP_GT150_EINT 0x0200 /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_MASK 0x0200 /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_SHIFT 9 /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT150_EINT_WIDTH 1 /* CHIP_GT150_EINT */
+#define WM8400_CHIP_GT115_EINT 0x0100 /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_MASK 0x0100 /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_SHIFT 8 /* CHIP_GT115_EINT */
+#define WM8400_CHIP_GT115_EINT_WIDTH 1 /* CHIP_GT115_EINT */
+#define WM8400_LINE_CMP_EINT 0x0080 /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_MASK 0x0080 /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_SHIFT 7 /* LINE_CMP_EINT */
+#define WM8400_LINE_CMP_EINT_WIDTH 1 /* LINE_CMP_EINT */
+#define WM8400_UVLO_EINT 0x0040 /* UVLO_EINT */
+#define WM8400_UVLO_EINT_MASK 0x0040 /* UVLO_EINT */
+#define WM8400_UVLO_EINT_SHIFT 6 /* UVLO_EINT */
+#define WM8400_UVLO_EINT_WIDTH 1 /* UVLO_EINT */
+#define WM8400_DC2_UV_EINT 0x0020 /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_MASK 0x0020 /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_SHIFT 5 /* DC2_UV_EINT */
+#define WM8400_DC2_UV_EINT_WIDTH 1 /* DC2_UV_EINT */
+#define WM8400_DC1_UV_EINT 0x0010 /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_MASK 0x0010 /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_SHIFT 4 /* DC1_UV_EINT */
+#define WM8400_DC1_UV_EINT_WIDTH 1 /* DC1_UV_EINT */
+#define WM8400_LDO4_UV_EINT 0x0008 /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_MASK 0x0008 /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_SHIFT 3 /* LDO4_UV_EINT */
+#define WM8400_LDO4_UV_EINT_WIDTH 1 /* LDO4_UV_EINT */
+#define WM8400_LDO3_UV_EINT 0x0004 /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_MASK 0x0004 /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_SHIFT 2 /* LDO3_UV_EINT */
+#define WM8400_LDO3_UV_EINT_WIDTH 1 /* LDO3_UV_EINT */
+#define WM8400_LDO2_UV_EINT 0x0002 /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_MASK 0x0002 /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_SHIFT 1 /* LDO2_UV_EINT */
+#define WM8400_LDO2_UV_EINT_WIDTH 1 /* LDO2_UV_EINT */
+#define WM8400_LDO1_UV_EINT 0x0001 /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_MASK 0x0001 /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_SHIFT 0 /* LDO1_UV_EINT */
+#define WM8400_LDO1_UV_EINT_WIDTH 1 /* LDO1_UV_EINT */
+
+/*
+ * R80 (0x50) - Interrupt Status 1 Mask
+ */
+#define WM8400_IM_MICD_CINT 0x8000 /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_MASK 0x8000 /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_SHIFT 15 /* IM_MICD_CINT */
+#define WM8400_IM_MICD_CINT_WIDTH 1 /* IM_MICD_CINT */
+#define WM8400_IM_MICSCD_CINT 0x4000 /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_MASK 0x4000 /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_SHIFT 14 /* IM_MICSCD_CINT */
+#define WM8400_IM_MICSCD_CINT_WIDTH 1 /* IM_MICSCD_CINT */
+#define WM8400_IM_JDL_CINT 0x2000 /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_MASK 0x2000 /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_SHIFT 13 /* IM_JDL_CINT */
+#define WM8400_IM_JDL_CINT_WIDTH 1 /* IM_JDL_CINT */
+#define WM8400_IM_JDR_CINT 0x1000 /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_MASK 0x1000 /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_SHIFT 12 /* IM_JDR_CINT */
+#define WM8400_IM_JDR_CINT_WIDTH 1 /* IM_JDR_CINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT 0x0800 /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_MASK 0x0800 /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_SHIFT 11 /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CODEC_SEQ_END_EINT_WIDTH 1 /* IM_CODEC_SEQ_END_EINT */
+#define WM8400_IM_CDEL_TO_EINT 0x0400 /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_MASK 0x0400 /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_SHIFT 10 /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CDEL_TO_EINT_WIDTH 1 /* IM_CDEL_TO_EINT */
+#define WM8400_IM_CHIP_GT150_EINT 0x0200 /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_MASK 0x0200 /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_SHIFT 9 /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT150_EINT_WIDTH 1 /* IM_CHIP_GT150_EINT */
+#define WM8400_IM_CHIP_GT115_EINT 0x0100 /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_MASK 0x0100 /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_SHIFT 8 /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_CHIP_GT115_EINT_WIDTH 1 /* IM_CHIP_GT115_EINT */
+#define WM8400_IM_LINE_CMP_EINT 0x0080 /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_MASK 0x0080 /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_SHIFT 7 /* IM_LINE_CMP_EINT */
+#define WM8400_IM_LINE_CMP_EINT_WIDTH 1 /* IM_LINE_CMP_EINT */
+#define WM8400_IM_UVLO_EINT 0x0040 /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_MASK 0x0040 /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_SHIFT 6 /* IM_UVLO_EINT */
+#define WM8400_IM_UVLO_EINT_WIDTH 1 /* IM_UVLO_EINT */
+#define WM8400_IM_DC2_UV_EINT 0x0020 /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_MASK 0x0020 /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_SHIFT 5 /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC2_UV_EINT_WIDTH 1 /* IM_DC2_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT 0x0010 /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_MASK 0x0010 /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_SHIFT 4 /* IM_DC1_UV_EINT */
+#define WM8400_IM_DC1_UV_EINT_WIDTH 1 /* IM_DC1_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT 0x0008 /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_MASK 0x0008 /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_SHIFT 3 /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO4_UV_EINT_WIDTH 1 /* IM_LDO4_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT 0x0004 /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_MASK 0x0004 /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_SHIFT 2 /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO3_UV_EINT_WIDTH 1 /* IM_LDO3_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT 0x0002 /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_MASK 0x0002 /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_SHIFT 1 /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO2_UV_EINT_WIDTH 1 /* IM_LDO2_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT 0x0001 /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_MASK 0x0001 /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_SHIFT 0 /* IM_LDO1_UV_EINT */
+#define WM8400_IM_LDO1_UV_EINT_WIDTH 1 /* IM_LDO1_UV_EINT */
+
+/*
+ * R81 (0x51) - Interrupt Levels
+ */
+#define WM8400_MICD_LVL 0x8000 /* MICD_LVL */
+#define WM8400_MICD_LVL_MASK 0x8000 /* MICD_LVL */
+#define WM8400_MICD_LVL_SHIFT 15 /* MICD_LVL */
+#define WM8400_MICD_LVL_WIDTH 1 /* MICD_LVL */
+#define WM8400_MICSCD_LVL 0x4000 /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_MASK 0x4000 /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_SHIFT 14 /* MICSCD_LVL */
+#define WM8400_MICSCD_LVL_WIDTH 1 /* MICSCD_LVL */
+#define WM8400_JDL_LVL 0x2000 /* JDL_LVL */
+#define WM8400_JDL_LVL_MASK 0x2000 /* JDL_LVL */
+#define WM8400_JDL_LVL_SHIFT 13 /* JDL_LVL */
+#define WM8400_JDL_LVL_WIDTH 1 /* JDL_LVL */
+#define WM8400_JDR_LVL 0x1000 /* JDR_LVL */
+#define WM8400_JDR_LVL_MASK 0x1000 /* JDR_LVL */
+#define WM8400_JDR_LVL_SHIFT 12 /* JDR_LVL */
+#define WM8400_JDR_LVL_WIDTH 1 /* JDR_LVL */
+#define WM8400_CODEC_SEQ_END_LVL 0x0800 /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_MASK 0x0800 /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_SHIFT 11 /* CODEC_SEQ_END_LVL */
+#define WM8400_CODEC_SEQ_END_LVL_WIDTH 1 /* CODEC_SEQ_END_LVL */
+#define WM8400_CDEL_TO_LVL 0x0400 /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_MASK 0x0400 /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_SHIFT 10 /* CDEL_TO_LVL */
+#define WM8400_CDEL_TO_LVL_WIDTH 1 /* CDEL_TO_LVL */
+#define WM8400_CHIP_GT150_LVL 0x0200 /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_MASK 0x0200 /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_SHIFT 9 /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT150_LVL_WIDTH 1 /* CHIP_GT150_LVL */
+#define WM8400_CHIP_GT115_LVL 0x0100 /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_MASK 0x0100 /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_SHIFT 8 /* CHIP_GT115_LVL */
+#define WM8400_CHIP_GT115_LVL_WIDTH 1 /* CHIP_GT115_LVL */
+#define WM8400_LINE_CMP_LVL 0x0080 /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_MASK 0x0080 /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_SHIFT 7 /* LINE_CMP_LVL */
+#define WM8400_LINE_CMP_LVL_WIDTH 1 /* LINE_CMP_LVL */
+#define WM8400_UVLO_LVL 0x0040 /* UVLO_LVL */
+#define WM8400_UVLO_LVL_MASK 0x0040 /* UVLO_LVL */
+#define WM8400_UVLO_LVL_SHIFT 6 /* UVLO_LVL */
+#define WM8400_UVLO_LVL_WIDTH 1 /* UVLO_LVL */
+#define WM8400_DC2_UV_LVL 0x0020 /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_MASK 0x0020 /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_SHIFT 5 /* DC2_UV_LVL */
+#define WM8400_DC2_UV_LVL_WIDTH 1 /* DC2_UV_LVL */
+#define WM8400_DC1_UV_LVL 0x0010 /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_MASK 0x0010 /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_SHIFT 4 /* DC1_UV_LVL */
+#define WM8400_DC1_UV_LVL_WIDTH 1 /* DC1_UV_LVL */
+#define WM8400_LDO4_UV_LVL 0x0008 /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_MASK 0x0008 /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_SHIFT 3 /* LDO4_UV_LVL */
+#define WM8400_LDO4_UV_LVL_WIDTH 1 /* LDO4_UV_LVL */
+#define WM8400_LDO3_UV_LVL 0x0004 /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_MASK 0x0004 /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_SHIFT 2 /* LDO3_UV_LVL */
+#define WM8400_LDO3_UV_LVL_WIDTH 1 /* LDO3_UV_LVL */
+#define WM8400_LDO2_UV_LVL 0x0002 /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_MASK 0x0002 /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_SHIFT 1 /* LDO2_UV_LVL */
+#define WM8400_LDO2_UV_LVL_WIDTH 1 /* LDO2_UV_LVL */
+#define WM8400_LDO1_UV_LVL 0x0001 /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_MASK 0x0001 /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_SHIFT 0 /* LDO1_UV_LVL */
+#define WM8400_LDO1_UV_LVL_WIDTH 1 /* LDO1_UV_LVL */
+
+/*
+ * R82 (0x52) - Shutdown Reason
+ */
+#define WM8400_SDR_CHIP_SOFTSD 0x2000 /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_MASK 0x2000 /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_SHIFT 13 /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_CHIP_SOFTSD_WIDTH 1 /* SDR_CHIP_SOFTSD */
+#define WM8400_SDR_NPDN 0x0800 /* SDR_NPDN */
+#define WM8400_SDR_NPDN_MASK 0x0800 /* SDR_NPDN */
+#define WM8400_SDR_NPDN_SHIFT 11 /* SDR_NPDN */
+#define WM8400_SDR_NPDN_WIDTH 1 /* SDR_NPDN */
+#define WM8400_SDR_CHIP_GT150 0x0200 /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_MASK 0x0200 /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_SHIFT 9 /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT150_WIDTH 1 /* SDR_CHIP_GT150 */
+#define WM8400_SDR_CHIP_GT115 0x0100 /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_MASK 0x0100 /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_SHIFT 8 /* SDR_CHIP_GT115 */
+#define WM8400_SDR_CHIP_GT115_WIDTH 1 /* SDR_CHIP_GT115 */
+#define WM8400_SDR_LINE_CMP 0x0080 /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_MASK 0x0080 /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_SHIFT 7 /* SDR_LINE_CMP */
+#define WM8400_SDR_LINE_CMP_WIDTH 1 /* SDR_LINE_CMP */
+#define WM8400_SDR_UVLO 0x0040 /* SDR_UVLO */
+#define WM8400_SDR_UVLO_MASK 0x0040 /* SDR_UVLO */
+#define WM8400_SDR_UVLO_SHIFT 6 /* SDR_UVLO */
+#define WM8400_SDR_UVLO_WIDTH 1 /* SDR_UVLO */
+#define WM8400_SDR_DC2_UV 0x0020 /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_MASK 0x0020 /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_SHIFT 5 /* SDR_DC2_UV */
+#define WM8400_SDR_DC2_UV_WIDTH 1 /* SDR_DC2_UV */
+#define WM8400_SDR_DC1_UV 0x0010 /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_MASK 0x0010 /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_SHIFT 4 /* SDR_DC1_UV */
+#define WM8400_SDR_DC1_UV_WIDTH 1 /* SDR_DC1_UV */
+#define WM8400_SDR_LDO4_UV 0x0008 /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_MASK 0x0008 /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_SHIFT 3 /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO4_UV_WIDTH 1 /* SDR_LDO4_UV */
+#define WM8400_SDR_LDO3_UV 0x0004 /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_MASK 0x0004 /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_SHIFT 2 /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO3_UV_WIDTH 1 /* SDR_LDO3_UV */
+#define WM8400_SDR_LDO2_UV 0x0002 /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_MASK 0x0002 /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_SHIFT 1 /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO2_UV_WIDTH 1 /* SDR_LDO2_UV */
+#define WM8400_SDR_LDO1_UV 0x0001 /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_MASK 0x0001 /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_SHIFT 0 /* SDR_LDO1_UV */
+#define WM8400_SDR_LDO1_UV_WIDTH 1 /* SDR_LDO1_UV */
+
+/*
+ * R84 (0x54) - Line Circuits
+ */
+#define WM8400_BG_LINE_COMP 0x8000 /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_MASK 0x8000 /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_SHIFT 15 /* BG_LINE_COMP */
+#define WM8400_BG_LINE_COMP_WIDTH 1 /* BG_LINE_COMP */
+#define WM8400_LINE_CMP_VTHI_MASK 0x00F0 /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_SHIFT 4 /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHI_WIDTH 4 /* LINE_CMP_VTHI - [7:4] */
+#define WM8400_LINE_CMP_VTHD_MASK 0x000F /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_SHIFT 0 /* LINE_CMP_VTHD - [3:0] */
+#define WM8400_LINE_CMP_VTHD_WIDTH 4 /* LINE_CMP_VTHD - [3:0] */
+
+u16 wm8400_reg_read(struct wm8400 *wm8400, u8 reg);
+int wm8400_block_read(struct wm8400 *wm8400, u8 reg, int count, u16 *data);
+int wm8400_set_bits(struct wm8400 *wm8400, u8 reg, u16 mask, u16 val);
+
+#endif
diff --git a/include/linux/mfd/wm8400.h b/include/linux/mfd/wm8400.h
new file mode 100644
index 00000000000..b46b566ac1a
--- /dev/null
+++ b/include/linux/mfd/wm8400.h
@@ -0,0 +1,40 @@
+/*
+ * wm8400 client interface
+ *
+ * Copyright 2008 Wolfson Microelectronics plc
+ *
+ * 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 __LINUX_MFD_WM8400_H
+#define __LINUX_MFD_WM8400_H
+
+#include <linux/regulator/machine.h>
+
+#define WM8400_LDO1 0
+#define WM8400_LDO2 1
+#define WM8400_LDO3 2
+#define WM8400_LDO4 3
+#define WM8400_DCDC1 4
+#define WM8400_DCDC2 5
+
+struct wm8400_platform_data {
+ int (*platform_init)(struct device *dev);
+};
+
+int wm8400_register_regulator(struct device *dev, int reg,
+ struct regulator_init_data *initdata);
+
+#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 3481a7d5bc0..d6a3f47e95c 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -131,6 +131,16 @@ struct usb_device_id {
#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100
#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200
+#define HID_ANY_ID (~0)
+
+struct hid_device_id {
+ __u16 bus;
+ __u32 vendor;
+ __u32 product;
+ kernel_ulong_t driver_data
+ __attribute__((aligned(sizeof(kernel_ulong_t))));
+};
+
/* s390 CCW devices */
struct ccw_device_id {
__u16 match_flags; /* which fields to match against */
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 30a1d63b6fb..cab2a85e2ee 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -5,8 +5,6 @@
*
* Author: Marco van Wieringen <mvw@planets.elm.net>
*
- * Version: $Id: mount.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
- *
*/
#ifndef _LINUX_MOUNT_H
#define _LINUX_MOUNT_H
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d3ea3de70a8..64875859d65 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -11,7 +11,7 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Donald J. Becker, <becker@cesdis.gsfc.nasa.gov>
- * Alan Cox, <Alan.Cox@linux.org>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Bjorn Ekwall. <bj0rn@blox.se>
* Pekka Riikonen <priikone@poseidon.pspt.fi>
*
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 108f47e5fd9..21269405ffe 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -38,6 +38,7 @@
#define NFSD_MAY_LOCK 32
#define NFSD_MAY_OWNER_OVERRIDE 64
#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/
+#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
@@ -125,7 +126,7 @@ int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
loff_t *, struct readdir_cd *, filldir_t);
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
- struct kstatfs *);
+ struct kstatfs *, int access);
int nfsd_notify_change(struct inode *, struct iattr *);
__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
diff --git a/include/linux/of.h b/include/linux/of.h
index 79886ade070..e2488f5e7cb 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -71,5 +71,8 @@ extern int of_n_size_cells(struct device_node *np);
extern const struct of_device_id *of_match_node(
const struct of_device_id *matches, const struct device_node *node);
extern int of_modalias_node(struct device_node *node, char *modalias, int len);
+extern int of_parse_phandles_with_args(struct device_node *np,
+ const char *list_name, const char *cells_name, int index,
+ struct device_node **out_node, const void **out_args);
#endif /* _LINUX_OF_H */
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 6a0d7cdb577..e1f83c5065c 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -1,5 +1,3 @@
-/* $Id: parport.h,v 1.1 1998/05/17 10:57:52 andrea Exp andrea $ */
-
/*
* Any part of this program may be used in documents licensed under
* the GNU Free Documentation License, Version 1.1 or any later version
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1176f1f177e..8edddc240e4 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -587,6 +587,7 @@
#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520
#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521
#define PCI_DEVICE_ID_MATROX_G400 0x0525
+#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530
#define PCI_DEVICE_ID_MATROX_G550 0x2527
#define PCI_DEVICE_ID_MATROX_VIA 0x4536
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index 1af82c4e17d..d82fe825d62 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -84,12 +84,6 @@ static inline struct pid_namespace *task_active_pid_ns(struct task_struct *tsk)
return tsk->nsproxy->pid_ns;
}
-static inline struct task_struct *task_child_reaper(struct task_struct *tsk)
-{
- BUG_ON(tsk != current);
- return tsk->nsproxy->pid_ns->child_reaper;
-}
-
void pidhash_init(void);
void pidmap_init(void);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 4dcce54b6d7..42de4003c4e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -419,7 +419,7 @@ extern void __suspend_report_result(const char *function, void *fn, int ret);
#define suspend_report_result(fn, ret) \
do { \
- __suspend_report_result(__FUNCTION__, fn, ret); \
+ __suspend_report_result(__func__, fn, ret); \
} while (0)
#else /* !CONFIG_PM_SLEEP */
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index be764e514e3..53b70fd1d9a 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -22,9 +22,11 @@ struct pnp_dev;
* Resource Management
*/
#ifdef CONFIG_PNP
-struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int);
+struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned long type,
+ unsigned int num);
#else
-static inline struct resource *pnp_get_resource(struct pnp_dev *dev, unsigned int type, unsigned int num)
+static inline struct resource *pnp_get_resource(struct pnp_dev *dev,
+ unsigned long type, unsigned int num)
{
return NULL;
}
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index fb61850d1cf..27d534f4470 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -139,7 +139,6 @@ extern int proc_readdir(struct file *, void *, filldir_t);
extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *);
extern const struct file_operations proc_kcore_operations;
-extern const struct file_operations ppc_htab_operations;
extern int pid_ns_prepare_proc(struct pid_namespace *ns);
extern void pid_ns_release_proc(struct pid_namespace *ns);
diff --git a/include/linux/profile.h b/include/linux/profile.h
index 7e7087239af..570045053ce 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -35,7 +35,9 @@ enum profile_type {
extern int prof_on __read_mostly;
/* init basic kernel profiler */
-void __init profile_init(void);
+int profile_init(void);
+int profile_setup(char *str);
+int create_proc_profile(void);
void profile_tick(int type);
/*
@@ -84,9 +86,9 @@ struct pt_regs;
#define prof_on 0
-static inline void profile_init(void)
+static inline int profile_init(void)
{
- return;
+ return 0;
}
static inline void profile_tick(int type)
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 376a05048bc..40401b55448 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -28,8 +28,6 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * Version: $Id: quota.h,v 2.0 1996/11/17 16:48:14 mvw Exp mvw $
*/
#ifndef _LINUX_QUOTA_
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index ca6b9b5c8d5..a558a4c1d35 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -3,9 +3,6 @@
* macros expand to the right source-code.
*
* Author: Marco van Wieringen <mvw@planets.elm.net>
- *
- * Version: $Id: quotaops.h,v 1.2 1998/01/15 16:22:26 ecd Exp $
- *
*/
#ifndef _LINUX_QUOTAOPS_
#define _LINUX_QUOTAOPS_
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index 1d712c7172a..e37d8056198 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -18,8 +18,8 @@
#include <linux/device.h>
#include <linux/regulator/consumer.h>
-struct regulator_constraints;
struct regulator_dev;
+struct regulator_init_data;
/**
* struct regulator_ops - regulator operations.
@@ -51,7 +51,7 @@ struct regulator_ops {
int output_uV, int load_uA);
/* the operations below are for configuration of regulator state when
- * it's parent PMIC enters a global STANBY/HIBERNATE state */
+ * its parent PMIC enters a global STANDBY/HIBERNATE state */
/* set regulator suspend voltage */
int (*set_suspend_voltage) (struct regulator_dev *, int uV);
@@ -85,15 +85,17 @@ struct regulator_desc {
struct module *owner;
};
-
struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
- void *reg_data);
+ struct device *dev, void *driver_data);
void regulator_unregister(struct regulator_dev *rdev);
int regulator_notifier_call_chain(struct regulator_dev *rdev,
unsigned long event, void *data);
void *rdev_get_drvdata(struct regulator_dev *rdev);
+struct device *rdev_get_dev(struct regulator_dev *rdev);
int rdev_get_id(struct regulator_dev *rdev);
+void *regulator_get_init_drvdata(struct regulator_init_data *reg_init_data);
+
#endif
diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h
index 11e737dbfcf..c6d69331a81 100644
--- a/include/linux/regulator/machine.h
+++ b/include/linux/regulator/machine.h
@@ -89,15 +89,33 @@ struct regulation_constraints {
unsigned apply_uV:1; /* apply uV constraint iff min == max */
};
-int regulator_set_supply(const char *regulator, const char *regulator_supply);
+/**
+ * struct regulator_consumer_supply - supply -> device mapping
+ *
+ * This maps a supply name to a device.
+ */
+struct regulator_consumer_supply {
+ struct device *dev; /* consumer */
+ const char *supply; /* consumer supply - e.g. "vcc" */
+};
-const char *regulator_get_supply(const char *regulator);
+/**
+ * struct regulator_init_data - regulator platform initialisation data.
+ *
+ * Initialisation constraints, our supply and consumers supplies.
+ */
+struct regulator_init_data {
+ struct device *supply_regulator_dev; /* or NULL for LINE */
-int regulator_set_machine_constraints(const char *regulator,
- struct regulation_constraints *constraints);
+ struct regulation_constraints constraints;
-int regulator_set_device_supply(const char *regulator, struct device *dev,
- const char *supply);
+ int num_consumer_supplies;
+ struct regulator_consumer_supply *consumer_supplies;
+
+ /* optional regulator machine specific init */
+ int (*regulator_init)(void *driver_data);
+ void *driver_data; /* core does not touch this */
+};
int regulator_suspend_prepare(suspend_state_t state);
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index e9963af16cd..bc5114d35e9 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -87,7 +87,7 @@ void reiserfs_warning(struct super_block *s, const char *fmt, ...);
if( !( cond ) ) \
reiserfs_panic( NULL, "reiserfs[%i]: assertion " scond " failed at " \
__FILE__ ":%i:%s: " format "\n", \
- in_interrupt() ? -1 : task_pid_nr(current), __LINE__ , __FUNCTION__ , ##args )
+ in_interrupt() ? -1 : task_pid_nr(current), __LINE__ , __func__ , ##args )
#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args)
diff --git a/include/linux/rtmutex.h b/include/linux/rtmutex.h
index 382bb795116..f19b00b7d53 100644
--- a/include/linux/rtmutex.h
+++ b/include/linux/rtmutex.h
@@ -54,7 +54,7 @@ struct hrtimer_sleeper;
#ifdef CONFIG_DEBUG_RT_MUTEXES
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \
, .name = #mutexname, .file = __FILE__, .line = __LINE__
-# define rt_mutex_init(mutex) __rt_mutex_init(mutex, __FUNCTION__)
+# define rt_mutex_init(mutex) __rt_mutex_init(mutex, __func__)
extern void rt_mutex_debug_task_free(struct task_struct *tsk);
#else
# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname)
diff --git a/include/linux/spi/orion_spi.h b/include/linux/spi/orion_spi.h
index b4d9fa6f797..decf6d8c77b 100644
--- a/include/linux/spi/orion_spi.h
+++ b/include/linux/spi/orion_spi.h
@@ -11,6 +11,7 @@
struct orion_spi_info {
u32 tclk; /* no <linux/clk.h> support yet */
+ u32 enable_clock_fix;
};
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index e5bfe01ee30..6f0ee1b84a4 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -104,6 +104,7 @@ struct rpc_create_args {
const struct rpc_timeout *timeout;
char *servername;
struct rpc_program *program;
+ u32 prognumber; /* overrides program->number */
u32 version;
rpc_authflavor_t authflavor;
unsigned long flags;
@@ -124,10 +125,10 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
-int rpcb_register(u32, u32, int, unsigned short, int *);
+int rpcb_register(u32, u32, int, unsigned short);
int rpcb_v4_register(const u32 program, const u32 version,
const struct sockaddr *address,
- const char *netid, int *result);
+ const char *netid);
int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
void rpcb_getport_async(struct rpc_task *);
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index dc69068d94c..3afe7fb403b 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -66,6 +66,7 @@ struct svc_serv {
struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary sockets */
struct timer_list sv_temptimer; /* timer for aging temporary sockets */
+ sa_family_t sv_family; /* listener's address family */
char * sv_name; /* service name */
@@ -265,17 +266,17 @@ struct svc_rqst {
/*
* Rigorous type checking on sockaddr type conversions
*/
-static inline struct sockaddr_in *svc_addr_in(struct svc_rqst *rqst)
+static inline struct sockaddr_in *svc_addr_in(const struct svc_rqst *rqst)
{
return (struct sockaddr_in *) &rqst->rq_addr;
}
-static inline struct sockaddr_in6 *svc_addr_in6(struct svc_rqst *rqst)
+static inline struct sockaddr_in6 *svc_addr_in6(const struct svc_rqst *rqst)
{
return (struct sockaddr_in6 *) &rqst->rq_addr;
}
-static inline struct sockaddr *svc_addr(struct svc_rqst *rqst)
+static inline struct sockaddr *svc_addr(const struct svc_rqst *rqst)
{
return (struct sockaddr *) &rqst->rq_addr;
}
@@ -381,18 +382,20 @@ struct svc_procedure {
/*
* Function prototypes.
*/
-struct svc_serv * svc_create(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv*));
+struct svc_serv *svc_create(struct svc_program *, unsigned int, sa_family_t,
+ void (*shutdown)(struct svc_serv *));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
struct svc_pool *pool);
void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv*), svc_thread_fn,
- struct module *);
+ sa_family_t, void (*shutdown)(struct svc_serv *),
+ svc_thread_fn, struct module *);
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
void svc_destroy(struct svc_serv *);
int svc_process(struct svc_rqst *);
-int svc_register(struct svc_serv *, int, unsigned short);
+int svc_register(const struct svc_serv *, const unsigned short,
+ const unsigned short);
+
void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space);
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h
index dc05b54bd3a..c14fe86dac5 100644
--- a/include/linux/sunrpc/svc_rdma.h
+++ b/include/linux/sunrpc/svc_rdma.h
@@ -72,6 +72,7 @@ extern atomic_t rdma_stat_sq_prod;
*/
struct svc_rdma_op_ctxt {
struct svc_rdma_op_ctxt *read_hdr;
+ struct svc_rdma_fastreg_mr *frmr;
int hdr_count;
struct xdr_buf arg;
struct list_head dto_q;
@@ -103,16 +104,30 @@ struct svc_rdma_chunk_sge {
int start; /* sge no for this chunk */
int count; /* sge count for this chunk */
};
+struct svc_rdma_fastreg_mr {
+ struct ib_mr *mr;
+ void *kva;
+ struct ib_fast_reg_page_list *page_list;
+ int page_list_len;
+ unsigned long access_flags;
+ unsigned long map_len;
+ enum dma_data_direction direction;
+ struct list_head frmr_list;
+};
struct svc_rdma_req_map {
+ struct svc_rdma_fastreg_mr *frmr;
unsigned long count;
union {
struct kvec sge[RPCSVC_MAXPAGES];
struct svc_rdma_chunk_sge ch[RPCSVC_MAXPAGES];
};
};
-
+#define RDMACTXT_F_FAST_UNREG 1
#define RDMACTXT_F_LAST_CTXT 2
+#define SVCRDMA_DEVCAP_FAST_REG 1 /* fast mr registration */
+#define SVCRDMA_DEVCAP_READ_W_INV 2 /* read w/ invalidate */
+
struct svcxprt_rdma {
struct svc_xprt sc_xprt; /* SVC transport structure */
struct rdma_cm_id *sc_cm_id; /* RDMA connection id */
@@ -136,6 +151,11 @@ struct svcxprt_rdma {
struct ib_cq *sc_rq_cq;
struct ib_cq *sc_sq_cq;
struct ib_mr *sc_phys_mr; /* MR for server memory */
+ u32 sc_dev_caps; /* distilled device caps */
+ u32 sc_dma_lkey; /* local dma key */
+ unsigned int sc_frmr_pg_list_len;
+ struct list_head sc_frmr_q;
+ spinlock_t sc_frmr_q_lock;
spinlock_t sc_lock; /* transport lock */
@@ -192,8 +212,13 @@ extern int svc_rdma_post_recv(struct svcxprt_rdma *);
extern int svc_rdma_create_listen(struct svc_serv *, int, struct sockaddr *);
extern struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *);
extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int);
+extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt);
extern struct svc_rdma_req_map *svc_rdma_get_req_map(void);
extern void svc_rdma_put_req_map(struct svc_rdma_req_map *);
+extern int svc_rdma_fastreg(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *);
+extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *);
+extern void svc_rdma_put_frmr(struct svcxprt_rdma *,
+ struct svc_rdma_fastreg_mr *);
extern void svc_sq_reap(struct svcxprt_rdma *);
extern void svc_rq_reap(struct svcxprt_rdma *);
extern struct svc_xprt_class svc_rdma_class;
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 8cff696dedf..483e10380aa 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -39,10 +39,7 @@ int svc_send(struct svc_rqst *);
void svc_drop(struct svc_rqst *);
void svc_sock_update_bufs(struct svc_serv *serv);
int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
-int svc_addsock(struct svc_serv *serv,
- int fd,
- char *name_return,
- int *proto);
+int svc_addsock(struct svc_serv *serv, int fd, char *name_return);
void svc_init_xprt_sock(void);
void svc_cleanup_xprt_sock(void);
diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h
new file mode 100644
index 00000000000..b18ec5533e8
--- /dev/null
+++ b/include/linux/swiotlb.h
@@ -0,0 +1,83 @@
+#ifndef __LINUX_SWIOTLB_H
+#define __LINUX_SWIOTLB_H
+
+#include <linux/types.h>
+
+struct device;
+struct dma_attrs;
+struct scatterlist;
+
+extern void
+swiotlb_init(void);
+
+extern void
+*swiotlb_alloc_coherent(struct device *hwdev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flags);
+
+extern void
+swiotlb_free_coherent(struct device *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
+extern dma_addr_t
+swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir);
+
+extern void
+swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir);
+
+extern dma_addr_t
+swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
+ int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir, struct dma_attrs *attrs);
+
+extern int
+swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+ int direction);
+
+extern void
+swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nents,
+ int direction);
+
+extern int
+swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
+ int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+ int nelems, int dir, struct dma_attrs *attrs);
+
+extern void
+swiotlb_sync_single_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir);
+
+extern void
+swiotlb_sync_sg_for_cpu(struct device *hwdev, struct scatterlist *sg,
+ int nelems, int dir);
+
+extern void
+swiotlb_sync_single_for_device(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir);
+
+extern void
+swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
+ int nelems, int dir);
+
+extern void
+swiotlb_sync_single_range_for_cpu(struct device *hwdev, dma_addr_t dev_addr,
+ unsigned long offset, size_t size, int dir);
+
+extern void
+swiotlb_sync_single_range_for_device(struct device *hwdev, dma_addr_t dev_addr,
+ unsigned long offset, size_t size,
+ int dir);
+
+extern int
+swiotlb_dma_mapping_error(struct device *hwdev, dma_addr_t dma_addr);
+
+extern int
+swiotlb_dma_supported(struct device *hwdev, u64 mask);
+
+#endif /* __LINUX_SWIOTLB_H */
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index d0437f36921..39d471d1163 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -972,7 +972,7 @@ extern int sysctl_perm(struct ctl_table_root *root,
typedef struct ctl_table ctl_table;
-typedef int ctl_handler (struct ctl_table *table, int __user *name, int nlen,
+typedef int ctl_handler (struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
diff --git a/include/linux/task_io_accounting.h b/include/linux/task_io_accounting.h
index 5e88afc9a2f..bdf855c2856 100644
--- a/include/linux/task_io_accounting.h
+++ b/include/linux/task_io_accounting.h
@@ -5,7 +5,7 @@
* Don't include this header file directly - it is designed to be dragged in via
* sched.h.
*
- * Blame akpm@osdl.org for all this.
+ * Blame Andrew Morton for all this.
*/
struct task_io_accounting {
diff --git a/include/linux/telephony.h b/include/linux/telephony.h
index 0d0cf2a1e7b..5b2b6261f19 100644
--- a/include/linux/telephony.h
+++ b/include/linux/telephony.h
@@ -28,10 +28,6 @@
* ON AN "AS IS" BASIS, AND QUICKNET TECHNOLOGIES, INC. HAS NO OBLIGATION
* TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
- * Version: $Revision: 4.2 $
- *
- * $Id: telephony.h,v 4.2 2001/08/06 07:09:43 craigs Exp $
- *
*****************************************************************************/
#ifndef TELEPHONY_H
diff --git a/include/linux/time.h b/include/linux/time.h
index e15206a7e82..51e883df0fa 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -29,6 +29,8 @@ struct timezone {
#ifdef __KERNEL__
+extern struct timezone sys_tz;
+
/* Parameters used to convert the timespec values: */
#define MSEC_PER_SEC 1000L
#define USEC_PER_MSEC 1000L
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 0081147a9fe..ef609f842fa 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -108,15 +108,6 @@ static inline int waitqueue_active(wait_queue_head_t *q)
return !list_empty(&q->task_list);
}
-/*
- * Used to distinguish between sync and async io wait context:
- * sync i/o typically specifies a NULL wait queue entry or a wait
- * queue entry bound to a task (current task) to wake up.
- * aio specifies a wait queue entry with an async notification
- * callback routine, not associated with any task.
- */
-#define is_sync_wait(wait) (!(wait) || ((wait)->private))
-
extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait);
extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
diff --git a/include/math-emu/op-2.h b/include/math-emu/op-2.h
index e193fb08fd5..4f26ecc1411 100644
--- a/include/math-emu/op-2.h
+++ b/include/math-emu/op-2.h
@@ -25,7 +25,7 @@
#ifndef __MATH_EMU_OP_2_H__
#define __MATH_EMU_OP_2_H__
-#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1
+#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0 = 0, X##_f1 = 0
#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1)
#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I)
#define _FP_FRAC_HIGH_2(X) (X##_f1)
diff --git a/include/math-emu/op-common.h b/include/math-emu/op-common.h
index bb46e7645d5..cc1ec396f8d 100644
--- a/include/math-emu/op-common.h
+++ b/include/math-emu/op-common.h
@@ -73,7 +73,7 @@ do { \
X##_c = FP_CLS_NAN; \
/* Check for signaling NaN */ \
if (!(_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs)) \
- FP_SET_EXCEPTION(FP_EX_INVALID); \
+ FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_SNAN); \
} \
break; \
} \
@@ -324,7 +324,7 @@ do { \
_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
R##_s = _FP_NANSIGN_##fs; \
R##_c = FP_CLS_NAN; \
- FP_SET_EXCEPTION(FP_EX_INVALID); \
+ FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ISI); \
break; \
} \
/* FALLTHRU */ \
@@ -431,7 +431,7 @@ do { \
R##_s = _FP_NANSIGN_##fs; \
R##_c = FP_CLS_NAN; \
_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
- FP_SET_EXCEPTION(FP_EX_INVALID); \
+ FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IMZ);\
break; \
\
default: \
@@ -490,11 +490,15 @@ do { \
break; \
\
case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
+ R##_s = _FP_NANSIGN_##fs; \
+ R##_c = FP_CLS_NAN; \
+ _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
+ FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_IDI);\
case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
R##_s = _FP_NANSIGN_##fs; \
R##_c = FP_CLS_NAN; \
_FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
- FP_SET_EXCEPTION(FP_EX_INVALID); \
+ FP_SET_EXCEPTION(FP_EX_INVALID | FP_EX_INVALID_ZDZ);\
break; \
\
default: \
diff --git a/include/math-emu/soft-fp.h b/include/math-emu/soft-fp.h
index a6f873b45f9..3f284bc0318 100644
--- a/include/math-emu/soft-fp.h
+++ b/include/math-emu/soft-fp.h
@@ -51,6 +51,25 @@
#ifndef FP_EX_INVALID
#define FP_EX_INVALID 0
#endif
+#ifndef FP_EX_INVALID_SNAN
+#define FP_EX_INVALID_SNAN 0
+#endif
+/* inf - inf */
+#ifndef FP_EX_INVALID_ISI
+#define FP_EX_INVALID_ISI 0
+#endif
+/* inf / inf */
+#ifndef FP_EX_INVALID_IDI
+#define FP_EX_INVALID_IDI 0
+#endif
+/* 0 / 0 */
+#ifndef FP_EX_INVALID_ZDZ
+#define FP_EX_INVALID_ZDZ 0
+#endif
+/* inf * 0 */
+#ifndef FP_EX_INVALID_IMZ
+#define FP_EX_INVALID_IMZ 0
+#endif
#ifndef FP_EX_OVERFLOW
#define FP_EX_OVERFLOW 0
#endif
diff --git a/include/media/saa7146.h b/include/media/saa7146.h
index 64a2ec746a3..c5a6e22a4b3 100644
--- a/include/media/saa7146.h
+++ b/include/media/saa7146.h
@@ -24,7 +24,7 @@
extern unsigned int saa7146_debug;
-//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__FUNCTION__)
+//#define DEBUG_PROLOG printk("(0x%08x)(0x%08x) %s: %s(): ",(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,RPS_ADDR0))),(dev==0?-1:(dev->mem==0?-1:saa7146_read(dev,IER))),KBUILD_MODNAME,__func__)
#ifndef DEBUG_VARIABLE
#define DEBUG_VARIABLE saa7146_debug
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index c3626c0ba9d..fb163e2e0de 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -61,7 +61,7 @@ extern unsigned int p9_debug_level;
do { \
if ((p9_debug_level & level) == level) \
printk(KERN_NOTICE "-- %s (%d): " \
- format , __FUNCTION__, task_pid_nr(current) , ## arg); \
+ format , __func__, task_pid_nr(current) , ## arg); \
} while (0)
#define PRINT_FCALL_ERROR(s, fcall) P9_DPRINTK(P9_DEBUG_ERROR, \
@@ -76,7 +76,7 @@ do { \
#define P9_EPRINTK(level, format, arg...) \
do { \
printk(level "9p: %s (%d): " \
- format , __FUNCTION__, task_pid_nr(current), ## arg); \
+ format , __func__, task_pid_nr(current), ## arg); \
} while (0)
/**
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 6f8418bf424..996d12df759 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -54,8 +54,8 @@
#define SOL_RFCOMM 18
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
-#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __FUNCTION__ , ## arg)
-#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __FUNCTION__ , ## arg)
+#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg)
+#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
/* Connection and socket states */
enum {
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
index 6048579d0b2..93a56de3594 100644
--- a/include/net/ieee80211.h
+++ b/include/net/ieee80211.h
@@ -114,7 +114,7 @@ extern u32 ieee80211_debug_level;
#define IEEE80211_DEBUG(level, fmt, args...) \
do { if (ieee80211_debug_level & (level)) \
printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
- in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
static inline bool ieee80211_ratelimit_debug(u32 level)
{
return (ieee80211_debug_level & level) && net_ratelimit();
diff --git a/include/net/ip.h b/include/net/ip.h
index 1cbccaf0de3..bc026ecb513 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -396,7 +396,7 @@ extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
int ipv4_doint_and_flush(ctl_table *ctl, int write,
struct file* filp, void __user *buffer,
size_t *lenp, loff_t *ppos);
-int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
+int ipv4_doint_and_flush_strategy(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
#ifdef CONFIG_PROC_FS
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 0b2071d9326..fe9fcf73c85 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -165,13 +165,13 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len,
do { \
if (level <= ip_vs_get_debug_level()) \
printk(KERN_DEBUG "Enter: %s, %s line %i\n", \
- __FUNCTION__, __FILE__, __LINE__); \
+ __func__, __FILE__, __LINE__); \
} while (0)
#define LeaveFunction(level) \
do { \
if (level <= ip_vs_get_debug_level()) \
printk(KERN_DEBUG "Leave: %s, %s line %i\n", \
- __FUNCTION__, __FILE__, __LINE__); \
+ __func__, __FILE__, __LINE__); \
} while (0)
#else
#define EnterFunction(level) do {} while (0)
diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h
index 08387553b57..7e582061b23 100644
--- a/include/net/irda/irda.h
+++ b/include/net/irda/irda.h
@@ -72,7 +72,7 @@ do { if (irda_debug >= (n)) \
#define IRDA_ASSERT(expr, func) \
do { if(!(expr)) { \
printk( "Assertion failed! %s:%s:%d %s\n", \
- __FILE__,__FUNCTION__,__LINE__,(#expr) ); \
+ __FILE__,__func__,__LINE__,(#expr) ); \
func } } while (0)
#define IRDA_ASSERT_LABEL(label) label
#else
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index a01b7c4dc76..11dd0137c6a 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -129,9 +129,8 @@ extern int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl,
void __user *buffer,
size_t *lenp,
loff_t *ppos);
-int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
- int nlen, void __user *oldval,
- size_t __user *oldlenp,
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl,
+ void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
#endif
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index 703305d0036..ed71b110edf 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -303,7 +303,7 @@ extern int sctp_debug_flag;
#define SCTP_ASSERT(expr, str, func) \
if (!(expr)) { \
SCTP_DEBUG_PRINTK("Assertion Failed: %s(%s) at %s:%s:%d\n", \
- str, (#expr), __FILE__, __FUNCTION__, __LINE__); \
+ str, (#expr), __FILE__, __func__, __LINE__); \
func; \
}
diff --git a/include/video/cyblafb.h b/include/video/cyblafb.h
index 71744057538..d3c1d4e2c8e 100644
--- a/include/video/cyblafb.h
+++ b/include/video/cyblafb.h
@@ -4,7 +4,7 @@
#endif
#if CYBLAFB_DEBUG
-#define debug(f,a...) printk("%s:" f, __FUNCTION__ , ## a);
+#define debug(f,a...) printk("%s:" f, __func__ , ## a);
#else
#define debug(f,a...)
#endif
diff --git a/include/video/neomagic.h b/include/video/neomagic.h
index 38910da0ae5..08b66378295 100644
--- a/include/video/neomagic.h
+++ b/include/video/neomagic.h
@@ -123,7 +123,6 @@ typedef volatile struct {
struct neofb_par {
struct vgastate state;
- struct mutex open_lock;
unsigned int ref_count;
unsigned char MiscOutReg; /* Misc */
diff --git a/include/video/radeon.h b/include/video/radeon.h
index 099ffa5e5be..d5dcaf154ba 100644
--- a/include/video/radeon.h
+++ b/include/video/radeon.h
@@ -386,7 +386,7 @@
#define SC_BOTTOM_RIGHT 0x16F0
#define SRC_SC_BOTTOM_RIGHT 0x16F4
#define RB2D_DSTCACHE_MODE 0x3428
-#define RB2D_DSTCACHE_CTLSTAT 0x342C
+#define RB2D_DSTCACHE_CTLSTAT_broken 0x342C /* do not use */
#define LVDS_GEN_CNTL 0x02d0
#define LVDS_PLL_CNTL 0x02d4
#define FP2_GEN_CNTL 0x0288
@@ -525,6 +525,9 @@
#define CRTC_DISPLAY_DIS (1 << 10)
#define CRTC_CRT_ON (1 << 15)
+/* DSTCACHE_MODE bits constants */
+#define RB2D_DC_AUTOFLUSH_ENABLE (1 << 8)
+#define RB2D_DC_DC_DISABLE_IGNORE_PE (1 << 17)
/* DSTCACHE_CTLSTAT bit constants */
#define RB2D_DC_FLUSH_2D (1 << 0)
@@ -532,6 +535,9 @@
#define RB2D_DC_FLUSH_ALL (RB2D_DC_FLUSH_2D | RB2D_DC_FREE_2D)
#define RB2D_DC_BUSY (1 << 31)
+/* DSTCACHE_MODE bits constants */
+#define RB2D_DC_AUTOFLUSH_ENABLE (1 << 8)
+#define RB2D_DC_DC_DISABLE_IGNORE_PE (1 << 17)
/* CRTC_GEN_CNTL bit constants */
#define CRTC_DBL_SCAN_EN 0x00000001
@@ -863,15 +869,10 @@
#define GMC_DST_16BPP_YVYU422 0x00000c00
#define GMC_DST_32BPP_AYUV444 0x00000e00
#define GMC_DST_16BPP_ARGB4444 0x00000f00
-#define GMC_SRC_MONO 0x00000000
-#define GMC_SRC_MONO_LBKGD 0x00001000
-#define GMC_SRC_DSTCOLOR 0x00003000
#define GMC_BYTE_ORDER_MSB_TO_LSB 0x00000000
#define GMC_BYTE_ORDER_LSB_TO_MSB 0x00004000
#define GMC_DP_CONVERSION_TEMP_9300 0x00008000
#define GMC_DP_CONVERSION_TEMP_6500 0x00000000
-#define GMC_DP_SRC_RECT 0x02000000
-#define GMC_DP_SRC_HOST 0x03000000
#define GMC_DP_SRC_HOST_BYTEALIGN 0x04000000
#define GMC_3D_FCN_EN_CLR 0x00000000
#define GMC_3D_FCN_EN_SET 0x08000000
@@ -882,6 +883,9 @@
#define GMC_WRITE_MASK_LEAVE 0x00000000
#define GMC_WRITE_MASK_SET 0x40000000
#define GMC_CLR_CMP_CNTL_DIS (1 << 28)
+#define GMC_SRC_DATATYPE_MASK (3 << 12)
+#define GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12)
+#define GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12)
#define GMC_SRC_DATATYPE_COLOR (3 << 12)
#define ROP3_S 0x00cc0000
#define ROP3_SRCCOPY 0x00cc0000
@@ -890,6 +894,7 @@
#define DP_SRC_SOURCE_MASK (7 << 24)
#define GMC_BRUSH_NONE (15 << 4)
#define DP_SRC_SOURCE_MEMORY (2 << 24)
+#define DP_SRC_SOURCE_HOST_DATA (3 << 24)
#define GMC_BRUSH_SOLIDCOLOR 0x000000d0
/* DP_MIX bit constants */
@@ -975,6 +980,12 @@
#define DISP_PWR_MAN_TV_ENABLE_RST (1 << 25)
#define DISP_PWR_MAN_AUTO_PWRUP_EN (1 << 26)
+/* RBBM_GUICNTL constants */
+#define RBBM_GUICNTL_HOST_DATA_SWAP_NONE (0 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_16BIT (1 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_32BIT (2 << 0)
+#define RBBM_GUICNTL_HOST_DATA_SWAP_HDW (3 << 0)
+
/* masks */
#define CONFIG_MEMSIZE_MASK 0x1f000000
diff --git a/include/video/s1d13xxxfb.h b/include/video/s1d13xxxfb.h
index c99d261df8f..fe41b840794 100644
--- a/include/video/s1d13xxxfb.h
+++ b/include/video/s1d13xxxfb.h
@@ -14,7 +14,8 @@
#define S1D13XXXFB_H
#define S1D_PALETTE_SIZE 256
-#define S1D_CHIP_REV 7 /* expected chip revision number for s1d13806 */
+#define S1D13506_CHIP_REV 4 /* expected chip revision number for s1d13506 */
+#define S1D13806_CHIP_REV 7 /* expected chip revision number for s1d13806 */
#define S1D_FBID "S1D13806"
#define S1D_DEVICENAME "s1d13806fb"
diff --git a/init/Kconfig b/init/Kconfig
index 8a8e2d00c40..5ceff3249a2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -713,6 +713,14 @@ config SHMEM
option replaces shmem and tmpfs with the much simpler ramfs code,
which may be appropriate on small systems without swap.
+config AIO
+ bool "Enable AIO support" if EMBEDDED
+ default y
+ help
+ This option enables POSIX asynchronous I/O which may by used
+ by some high performance threaded applications. Disabling
+ this option saves about 7k.
+
config VM_EVENT_COUNTERS
default y
bool "Enable VM event counters for /proc/vmstat" if EMBEDDED
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 693d24694a6..48b3fadd83e 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -12,7 +12,12 @@
* The code for that is here.
*/
-static int __initdata raid_noautodetect, raid_autopart;
+#ifdef CONFIG_MD_AUTODETECT
+static int __initdata raid_noautodetect;
+#else
+static int __initdata raid_noautodetect=1;
+#endif
+static int __initdata raid_autopart;
static struct {
int minor;
@@ -252,6 +257,8 @@ static int __init raid_setup(char *str)
if (!strncmp(str, "noautodetect", wlen))
raid_noautodetect = 1;
+ if (!strncmp(str, "autodetect", wlen))
+ raid_noautodetect = 0;
if (strncmp(str, "partitionable", wlen)==0)
raid_autopart = 1;
if (strncmp(str, "part", wlen)==0)
@@ -264,17 +271,32 @@ static int __init raid_setup(char *str)
__setup("raid=", raid_setup);
__setup("md=", md_setup);
+static void autodetect_raid(void)
+{
+ int fd;
+
+ /*
+ * Since we don't want to detect and use half a raid array, we need to
+ * wait for the known devices to complete their probing
+ */
+ printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
+ printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
+ while (driver_probe_done() < 0)
+ msleep(100);
+ fd = sys_open("/dev/md0", 0, 0);
+ if (fd >= 0) {
+ sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
+ sys_close(fd);
+ }
+}
+
void __init md_run_setup(void)
{
create_dev("/dev/md0", MKDEV(MD_MAJOR, 0));
+
if (raid_noautodetect)
- printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n");
- else {
- int fd = sys_open("/dev/md0", 0, 0);
- if (fd >= 0) {
- sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
- sys_close(fd);
- }
- }
+ printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=autodetect will force)\n");
+ else
+ autodetect_raid();
md_setup_drive();
}
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c
index fedef93b586..a7c748fa977 100644
--- a/init/do_mounts_rd.c
+++ b/init/do_mounts_rd.c
@@ -71,7 +71,7 @@ identify_ramdisk_image(int fd, int start_block)
sys_read(fd, buf, size);
/*
- * If it matches the gzip magic numbers, return -1
+ * If it matches the gzip magic numbers, return 0
*/
if (buf[0] == 037 && ((buf[1] == 0213) || (buf[1] == 0236))) {
printk(KERN_NOTICE
diff --git a/init/initramfs.c b/init/initramfs.c
index 644fc01ad5f..4f5ba75aaa7 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/syscalls.h>
+#include <linux/utime.h>
static __initdata char *message;
static void __init error(char *x)
@@ -72,6 +73,49 @@ static void __init free_hash(void)
}
}
+static long __init do_utime(char __user *filename, time_t mtime)
+{
+ struct timespec t[2];
+
+ t[0].tv_sec = mtime;
+ t[0].tv_nsec = 0;
+ t[1].tv_sec = mtime;
+ t[1].tv_nsec = 0;
+
+ return do_utimes(AT_FDCWD, filename, t, AT_SYMLINK_NOFOLLOW);
+}
+
+static __initdata LIST_HEAD(dir_list);
+struct dir_entry {
+ struct list_head list;
+ char *name;
+ time_t mtime;
+};
+
+static void __init dir_add(const char *name, time_t mtime)
+{
+ struct dir_entry *de = kmalloc(sizeof(struct dir_entry), GFP_KERNEL);
+ if (!de)
+ panic("can't allocate dir_entry buffer");
+ INIT_LIST_HEAD(&de->list);
+ de->name = kstrdup(name, GFP_KERNEL);
+ de->mtime = mtime;
+ list_add(&de->list, &dir_list);
+}
+
+static void __init dir_utime(void)
+{
+ struct dir_entry *de, *tmp;
+ list_for_each_entry_safe(de, tmp, &dir_list, list) {
+ list_del(&de->list);
+ do_utime(de->name, de->mtime);
+ kfree(de->name);
+ kfree(de);
+ }
+}
+
+static __initdata time_t mtime;
+
/* cpio header parsing */
static __initdata unsigned long ino, major, minor, nlink;
@@ -97,6 +141,7 @@ static void __init parse_header(char *s)
uid = parsed[2];
gid = parsed[3];
nlink = parsed[4];
+ mtime = parsed[5];
body_len = parsed[6];
major = parsed[7];
minor = parsed[8];
@@ -130,6 +175,7 @@ static inline void __init eat(unsigned n)
count -= n;
}
+static __initdata char *vcollected;
static __initdata char *collected;
static __initdata int remains;
static __initdata char *collect;
@@ -271,6 +317,7 @@ static int __init do_name(void)
if (wfd >= 0) {
sys_fchown(wfd, uid, gid);
sys_fchmod(wfd, mode);
+ vcollected = kstrdup(collected, GFP_KERNEL);
state = CopyFile;
}
}
@@ -278,12 +325,14 @@ static int __init do_name(void)
sys_mkdir(collected, mode);
sys_chown(collected, uid, gid);
sys_chmod(collected, mode);
+ dir_add(collected, mtime);
} else if (S_ISBLK(mode) || S_ISCHR(mode) ||
S_ISFIFO(mode) || S_ISSOCK(mode)) {
if (maybe_link() == 0) {
sys_mknod(collected, mode, rdev);
sys_chown(collected, uid, gid);
sys_chmod(collected, mode);
+ do_utime(collected, mtime);
}
}
return 0;
@@ -294,6 +343,8 @@ static int __init do_copy(void)
if (count >= body_len) {
sys_write(wfd, victim, body_len);
sys_close(wfd);
+ do_utime(vcollected, mtime);
+ kfree(vcollected);
eat(body_len);
state = SkipIt;
return 0;
@@ -311,6 +362,7 @@ static int __init do_symlink(void)
clean_path(collected, 0);
sys_symlink(collected + N_ALIGN(name_len), collected);
sys_lchown(collected, uid, gid);
+ do_utime(collected, mtime);
state = SkipIt;
next_state = Reset;
return 0;
@@ -466,6 +518,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len, int check_only)
buf += inptr;
len -= inptr;
}
+ dir_utime();
kfree(window);
kfree(name_buf);
kfree(symlink_buf);
diff --git a/init/main.c b/init/main.c
index 3820323c4c8..27f6bf6108e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -708,7 +708,7 @@ int do_one_initcall(initcall_t fn)
int result;
if (initcall_debug) {
- printk("calling %pF\n", fn);
+ printk("calling %pF @ %i\n", fn, task_pid_nr(current));
t0 = ktime_get();
}
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index 69bc85978ba..0dfebc50942 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -131,7 +131,7 @@ static int proc_ipcauto_dointvec_minmax(ctl_table *table, int write,
#ifdef CONFIG_SYSCTL_SYSCALL
/* The generic sysctl ipc data routine. */
-static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
+static int sysctl_ipc_data(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -169,14 +169,13 @@ static int sysctl_ipc_data(ctl_table *table, int __user *name, int nlen,
return 1;
}
-static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
- int nlen, void __user *oldval, size_t __user *oldlenp,
+static int sysctl_ipc_registered_data(ctl_table *table,
+ void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
int rc;
- rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
- newlen);
+ rc = sysctl_ipc_data(table, oldval, oldlenp, newval, newlen);
if (newval && newlen && rc > 0)
/*
diff --git a/ipc/sem.c b/ipc/sem.c
index bf1bc36cb7e..082122469b1 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -504,7 +504,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
return semzcnt;
}
-void free_un(struct rcu_head *head)
+static void free_un(struct rcu_head *head)
{
struct sem_undo *un = container_of(head, struct sem_undo, rcu);
kfree(un);
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index a0123d75ec9..8c6e1c17e6d 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -2735,6 +2735,8 @@ void cgroup_fork_callbacks(struct task_struct *child)
* Called on every change to mm->owner. mm_init_owner() does not
* invoke this routine, since it assigns the mm->owner the first time
* and does not change it.
+ *
+ * The callbacks are invoked with mmap_sem held in read mode.
*/
void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
{
@@ -2750,7 +2752,7 @@ void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
if (oldcgrp == newcgrp)
continue;
if (ss->mm_owner_changed)
- ss->mm_owner_changed(ss, oldcgrp, newcgrp);
+ ss->mm_owner_changed(ss, oldcgrp, newcgrp, new);
}
}
}
diff --git a/kernel/compat.c b/kernel/compat.c
index 32c254a8ab9..143990e48cb 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -26,6 +26,64 @@
#include <asm/uaccess.h>
+/*
+ * Note that the native side is already converted to a timespec, because
+ * that's what we want anyway.
+ */
+static int compat_get_timeval(struct timespec *o,
+ struct compat_timeval __user *i)
+{
+ long usec;
+
+ if (get_user(o->tv_sec, &i->tv_sec) ||
+ get_user(usec, &i->tv_usec))
+ return -EFAULT;
+ o->tv_nsec = usec * 1000;
+ return 0;
+}
+
+static int compat_put_timeval(struct compat_timeval __user *o,
+ struct timeval *i)
+{
+ return (put_user(i->tv_sec, &o->tv_sec) ||
+ put_user(i->tv_usec, &o->tv_usec)) ? -EFAULT : 0;
+}
+
+asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv,
+ struct timezone __user *tz)
+{
+ if (tv) {
+ struct timeval ktv;
+ do_gettimeofday(&ktv);
+ if (compat_put_timeval(tv, &ktv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv,
+ struct timezone __user *tz)
+{
+ struct timespec kts;
+ struct timezone ktz;
+
+ if (tv) {
+ if (compat_get_timeval(&kts, tv))
+ return -EFAULT;
+ }
+ if (tz) {
+ if (copy_from_user(&ktz, tz, sizeof(ktz)))
+ return -EFAULT;
+ }
+
+ return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
+}
+
int get_compat_timespec(struct timespec *ts, const struct compat_timespec __user *cts)
{
return (!access_ok(VERIFY_READ, cts, sizeof(*cts)) ||
diff --git a/kernel/dma.c b/kernel/dma.c
index d2c60a82279..f903189c530 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -1,4 +1,4 @@
-/* $Id: dma.c,v 1.7 1994/12/28 03:35:33 root Exp root $
+/*
* linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c.
*
* Written by Hennus Bergman, 1992.
diff --git a/kernel/exit.c b/kernel/exit.c
index 85a83c83185..0ef4673e351 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -640,24 +640,23 @@ retry:
assign_new_owner:
BUG_ON(c == p);
get_task_struct(c);
+ read_unlock(&tasklist_lock);
+ down_write(&mm->mmap_sem);
/*
* The task_lock protects c->mm from changing.
* We always want mm->owner->mm == mm
*/
task_lock(c);
- /*
- * Delay read_unlock() till we have the task_lock()
- * to ensure that c does not slip away underneath us
- */
- read_unlock(&tasklist_lock);
if (c->mm != mm) {
task_unlock(c);
+ up_write(&mm->mmap_sem);
put_task_struct(c);
goto retry;
}
cgroup_mm_owner_callbacks(mm->owner, c);
mm->owner = c;
task_unlock(c);
+ up_write(&mm->mmap_sem);
put_task_struct(c);
}
#endif /* CONFIG_MM_OWNER */
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 38fc10ac754..5072cf1685a 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -260,7 +260,6 @@ const char *kallsyms_lookup(unsigned long addr,
/* see if it's in a module */
return module_address_lookup(addr, symbolsize, offset, modname,
namebuf);
- return NULL;
}
int lookup_symbol_name(unsigned long addr, char *symname)
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 2456d1a0bef..ab7dd08472f 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -265,7 +265,7 @@ static void __call_usermodehelper(struct work_struct *work)
}
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/*
* If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
* (used for preventing user land processes from being created after the user
@@ -288,39 +288,37 @@ static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
*/
#define RUNNING_HELPERS_TIMEOUT (5 * HZ)
-static int usermodehelper_pm_callback(struct notifier_block *nfb,
- unsigned long action,
- void *ignored)
+/**
+ * usermodehelper_disable - prevent new helpers from being started
+ */
+int usermodehelper_disable(void)
{
long retval;
- switch (action) {
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- usermodehelper_disabled = 1;
- smp_mb();
- /*
- * From now on call_usermodehelper_exec() won't start any new
- * helpers, so it is sufficient if running_helpers turns out to
- * be zero at one point (it may be increased later, but that
- * doesn't matter).
- */
- retval = wait_event_timeout(running_helpers_waitq,
+ usermodehelper_disabled = 1;
+ smp_mb();
+ /*
+ * From now on call_usermodehelper_exec() won't start any new
+ * helpers, so it is sufficient if running_helpers turns out to
+ * be zero at one point (it may be increased later, but that
+ * doesn't matter).
+ */
+ retval = wait_event_timeout(running_helpers_waitq,
atomic_read(&running_helpers) == 0,
RUNNING_HELPERS_TIMEOUT);
- if (retval) {
- return NOTIFY_OK;
- } else {
- usermodehelper_disabled = 0;
- return NOTIFY_BAD;
- }
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- usermodehelper_disabled = 0;
- return NOTIFY_OK;
- }
+ if (retval)
+ return 0;
- return NOTIFY_DONE;
+ usermodehelper_disabled = 0;
+ return -EAGAIN;
+}
+
+/**
+ * usermodehelper_enable - allow new helpers to be started again
+ */
+void usermodehelper_enable(void)
+{
+ usermodehelper_disabled = 0;
}
static void helper_lock(void)
@@ -334,18 +332,12 @@ static void helper_unlock(void)
if (atomic_dec_and_test(&running_helpers))
wake_up(&running_helpers_waitq);
}
-
-static void register_pm_notifier_callback(void)
-{
- pm_notifier(usermodehelper_pm_callback, 0);
-}
-#else /* CONFIG_PM */
+#else /* CONFIG_PM_SLEEP */
#define usermodehelper_disabled 0
static inline void helper_lock(void) {}
static inline void helper_unlock(void) {}
-static inline void register_pm_notifier_callback(void) {}
-#endif /* CONFIG_PM */
+#endif /* CONFIG_PM_SLEEP */
/**
* call_usermodehelper_setup - prepare to call a usermode helper
@@ -515,5 +507,4 @@ void __init usermodehelper_init(void)
{
khelper_wq = create_singlethread_workqueue("khelper");
BUG_ON(!khelper_wq);
- register_pm_notifier_callback();
}
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 75bc2cd9ebc..8b57a2597f2 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -404,7 +404,7 @@ void kretprobe_hash_lock(struct task_struct *tsk,
spin_lock_irqsave(hlist_lock, *flags);
}
-void kretprobe_table_lock(unsigned long hash, unsigned long *flags)
+static void kretprobe_table_lock(unsigned long hash, unsigned long *flags)
{
spinlock_t *hlist_lock = kretprobe_table_lock_ptr(hash);
spin_lock_irqsave(hlist_lock, *flags);
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index e53bc30e9ba..08dd8ed86c7 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kexec.h>
+#include <linux/profile.h>
#include <linux/sched.h>
#define KERNEL_ATTR_RO(_name) \
@@ -53,6 +54,37 @@ static ssize_t uevent_helper_store(struct kobject *kobj,
KERNEL_ATTR_RW(uevent_helper);
#endif
+#ifdef CONFIG_PROFILING
+static ssize_t profiling_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", prof_on);
+}
+static ssize_t profiling_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int ret;
+
+ if (prof_on)
+ return -EEXIST;
+ /*
+ * This eventually calls into get_option() which
+ * has a ton of callers and is not const. It is
+ * easiest to cast it away here.
+ */
+ profile_setup((char *)buf);
+ ret = profile_init();
+ if (ret)
+ return ret;
+ ret = create_proc_profile();
+ if (ret)
+ return ret;
+ return count;
+}
+KERNEL_ATTR_RW(profiling);
+#endif
+
#ifdef CONFIG_KEXEC
static ssize_t kexec_loaded_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
@@ -109,6 +141,9 @@ static struct attribute * kernel_attrs[] = {
&uevent_seqnum_attr.attr,
&uevent_helper_attr.attr,
#endif
+#ifdef CONFIG_PROFILING
+ &profiling_attr.attr,
+#endif
#ifdef CONFIG_KEXEC
&kexec_loaded_attr.attr,
&kexec_crash_loaded_attr.attr,
diff --git a/kernel/module.c b/kernel/module.c
index 9db11911e04..dd9ac6ad5cb 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -100,7 +100,7 @@ static inline int strong_try_module_get(struct module *mod)
static inline void add_taint_module(struct module *mod, unsigned flag)
{
add_taint(flag);
- mod->taints |= flag;
+ mod->taints |= (1U << flag);
}
/*
@@ -923,7 +923,7 @@ static const char vermagic[] = VERMAGIC_STRING;
static int try_to_force_load(struct module *mod, const char *symname)
{
#ifdef CONFIG_MODULE_FORCE_LOAD
- if (!(tainted & TAINT_FORCED_MODULE))
+ if (!test_taint(TAINT_FORCED_MODULE))
printk("%s: no version for \"%s\" found: kernel tainted.\n",
mod->name, symname);
add_taint_module(mod, TAINT_FORCED_MODULE);
@@ -1033,7 +1033,7 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
const unsigned long *crc;
ret = find_symbol(name, &owner, &crc,
- !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
+ !(mod->taints & (1 << TAINT_PROPRIETARY_MODULE)), true);
if (!IS_ERR_VALUE(ret)) {
/* use_module can fail due to OOM,
or module initialization or unloading */
@@ -1634,7 +1634,7 @@ static void set_license(struct module *mod, const char *license)
license = "unspecified";
if (!license_is_gpl_compatible(license)) {
- if (!(tainted & TAINT_PROPRIETARY_MODULE))
+ if (!test_taint(TAINT_PROPRIETARY_MODULE))
printk(KERN_WARNING "%s: module license '%s' taints "
"kernel.\n", mod->name, license);
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
@@ -2552,9 +2552,9 @@ static char *module_flags(struct module *mod, char *buf)
mod->state == MODULE_STATE_GOING ||
mod->state == MODULE_STATE_COMING) {
buf[bx++] = '(';
- if (mod->taints & TAINT_PROPRIETARY_MODULE)
+ if (mod->taints & (1 << TAINT_PROPRIETARY_MODULE))
buf[bx++] = 'P';
- if (mod->taints & TAINT_FORCED_MODULE)
+ if (mod->taints & (1 << TAINT_FORCED_MODULE))
buf[bx++] = 'F';
/*
* TAINT_FORCED_RMMOD: could be added.
diff --git a/kernel/panic.c b/kernel/panic.c
index 12c5a0a6c89..f290e8e866f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -23,7 +23,7 @@
#include <linux/kallsyms.h>
int panic_on_oops;
-int tainted;
+static unsigned long tainted_mask;
static int pause_on_oops;
static int pause_on_oops_flag;
static DEFINE_SPINLOCK(pause_on_oops_lock);
@@ -143,6 +143,26 @@ NORET_TYPE void panic(const char * fmt, ...)
EXPORT_SYMBOL(panic);
+
+struct tnt {
+ u8 bit;
+ char true;
+ char false;
+};
+
+static const struct tnt tnts[] = {
+ { TAINT_PROPRIETARY_MODULE, 'P', 'G' },
+ { TAINT_FORCED_MODULE, 'F', ' ' },
+ { TAINT_UNSAFE_SMP, 'S', ' ' },
+ { TAINT_FORCED_RMMOD, 'R', ' ' },
+ { TAINT_MACHINE_CHECK, 'M', ' ' },
+ { TAINT_BAD_PAGE, 'B', ' ' },
+ { TAINT_USER, 'U', ' ' },
+ { TAINT_DIE, 'D', ' ' },
+ { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
+ { TAINT_WARN, 'W', ' ' },
+};
+
/**
* print_tainted - return a string to represent the kernel taint state.
*
@@ -158,32 +178,41 @@ EXPORT_SYMBOL(panic);
*
* The string is overwritten by the next call to print_taint().
*/
-
const char *print_tainted(void)
{
- static char buf[20];
- if (tainted) {
- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c",
- tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
- tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
- tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
- tainted & TAINT_FORCED_RMMOD ? 'R' : ' ',
- tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
- tainted & TAINT_BAD_PAGE ? 'B' : ' ',
- tainted & TAINT_USER ? 'U' : ' ',
- tainted & TAINT_DIE ? 'D' : ' ',
- tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ',
- tainted & TAINT_WARN ? 'W' : ' ');
- }
- else
+ static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ") + 1];
+
+ if (tainted_mask) {
+ char *s;
+ int i;
+
+ s = buf + sprintf(buf, "Tainted: ");
+ for (i = 0; i < ARRAY_SIZE(tnts); i++) {
+ const struct tnt *t = &tnts[i];
+ *s++ = test_bit(t->bit, &tainted_mask) ?
+ t->true : t->false;
+ }
+ *s = 0;
+ } else
snprintf(buf, sizeof(buf), "Not tainted");
return(buf);
}
+int test_taint(unsigned flag)
+{
+ return test_bit(flag, &tainted_mask);
+}
+EXPORT_SYMBOL(test_taint);
+
+unsigned long get_taint(void)
+{
+ return tainted_mask;
+}
+
void add_taint(unsigned flag)
{
debug_locks = 0; /* can't trust the integrity of the kernel anymore */
- tainted |= flag;
+ set_bit(flag, &tainted_mask);
}
EXPORT_SYMBOL(add_taint);
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index bbd85c60f74..331f9836383 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -14,6 +14,7 @@
#include <linux/reboot.h>
#include <linux/string.h>
#include <linux/device.h>
+#include <linux/kmod.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/mount.h>
@@ -520,6 +521,10 @@ int hibernate(void)
if (error)
goto Exit;
+ error = usermodehelper_disable();
+ if (error)
+ goto Exit;
+
/* Allocate memory management structures */
error = create_basic_memory_bitmaps();
if (error)
@@ -558,6 +563,7 @@ int hibernate(void)
thaw_processes();
Finish:
free_basic_memory_bitmaps();
+ usermodehelper_enable();
Exit:
pm_notifier_call_chain(PM_POST_HIBERNATION);
pm_restore_console();
@@ -634,6 +640,10 @@ static int software_resume(void)
if (error)
goto Finish;
+ error = usermodehelper_disable();
+ if (error)
+ goto Finish;
+
error = create_basic_memory_bitmaps();
if (error)
goto Finish;
@@ -656,6 +666,7 @@ static int software_resume(void)
thaw_processes();
Done:
free_basic_memory_bitmaps();
+ usermodehelper_enable();
Finish:
pm_notifier_call_chain(PM_POST_RESTORE);
pm_restore_console();
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 540b16b6856..19122cf6d82 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -14,6 +14,7 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/kmod.h>
#include <linux/init.h>
#include <linux/console.h>
#include <linux/cpu.h>
@@ -237,6 +238,10 @@ static int suspend_prepare(void)
if (error)
goto Finish;
+ error = usermodehelper_disable();
+ if (error)
+ goto Finish;
+
if (suspend_freeze_processes()) {
error = -EAGAIN;
goto Thaw;
@@ -256,6 +261,7 @@ static int suspend_prepare(void)
Thaw:
suspend_thaw_processes();
+ usermodehelper_enable();
Finish:
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
@@ -376,6 +382,7 @@ int suspend_devices_and_enter(suspend_state_t state)
static void suspend_finish(void)
{
suspend_thaw_processes();
+ usermodehelper_enable();
pm_notifier_call_chain(PM_POST_SUSPEND);
pm_restore_console();
}
diff --git a/kernel/power/user.c b/kernel/power/user.c
index a6332a31326..005b93d839b 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -212,13 +212,20 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
case SNAPSHOT_FREEZE:
if (data->frozen)
break;
+
printk("Syncing filesystems ... ");
sys_sync();
printk("done.\n");
- error = freeze_processes();
+ error = usermodehelper_disable();
if (error)
+ break;
+
+ error = freeze_processes();
+ if (error) {
thaw_processes();
+ usermodehelper_enable();
+ }
if (!error)
data->frozen = 1;
break;
@@ -227,6 +234,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
if (!data->frozen || data->ready)
break;
thaw_processes();
+ usermodehelper_enable();
data->frozen = 0;
break;
diff --git a/kernel/printk.c b/kernel/printk.c
index a430fd04008..fbd94bdaa74 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -13,7 +13,7 @@
* Fixed SMP synchronization, 08/08/99, Manfred Spraul
* manfred@colorfullife.com
* Rewrote bits to get rid of console_lock
- * 01Mar01 Andrew Morton <andrewm@uow.edu.au>
+ * 01Mar01 Andrew Morton
*/
#include <linux/kernel.h>
@@ -593,6 +593,8 @@ static int have_callable_console(void)
*
* See also:
* printf(3)
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
*/
asmlinkage int printk(const char *fmt, ...)
diff --git a/kernel/profile.c b/kernel/profile.c
index cd26bed4cc2..a9e422df6bf 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -22,6 +22,8 @@
#include <linux/cpu.h>
#include <linux/highmem.h>
#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <asm/sections.h>
#include <asm/irq_regs.h>
#include <asm/ptrace.h>
@@ -50,11 +52,11 @@ static DEFINE_PER_CPU(int, cpu_profile_flip);
static DEFINE_MUTEX(profile_flip_mutex);
#endif /* CONFIG_SMP */
-static int __init profile_setup(char *str)
+int profile_setup(char *str)
{
- static char __initdata schedstr[] = "schedule";
- static char __initdata sleepstr[] = "sleep";
- static char __initdata kvmstr[] = "kvm";
+ static char schedstr[] = "schedule";
+ static char sleepstr[] = "sleep";
+ static char kvmstr[] = "kvm";
int par;
if (!strncmp(str, sleepstr, strlen(sleepstr))) {
@@ -100,14 +102,33 @@ static int __init profile_setup(char *str)
__setup("profile=", profile_setup);
-void __init profile_init(void)
+int profile_init(void)
{
+ int buffer_bytes;
if (!prof_on)
- return;
+ return 0;
/* only text is profiled */
prof_len = (_etext - _stext) >> prof_shift;
- prof_buffer = alloc_bootmem(prof_len*sizeof(atomic_t));
+ buffer_bytes = prof_len*sizeof(atomic_t);
+ if (!slab_is_available()) {
+ prof_buffer = alloc_bootmem(buffer_bytes);
+ return 0;
+ }
+
+ prof_buffer = kzalloc(buffer_bytes, GFP_KERNEL);
+ if (prof_buffer)
+ return 0;
+
+ prof_buffer = alloc_pages_exact(buffer_bytes, GFP_KERNEL|__GFP_ZERO);
+ if (prof_buffer)
+ return 0;
+
+ prof_buffer = vmalloc(buffer_bytes);
+ if (prof_buffer)
+ return 0;
+
+ return -ENOMEM;
}
/* Profile event notifications */
@@ -527,7 +548,7 @@ static void __init profile_nop(void *unused)
{
}
-static int __init create_hash_tables(void)
+static int create_hash_tables(void)
{
int cpu;
@@ -575,14 +596,14 @@ out_cleanup:
#define create_hash_tables() ({ 0; })
#endif
-static int __init create_proc_profile(void)
+int create_proc_profile(void)
{
struct proc_dir_entry *entry;
if (!prof_on)
return 0;
if (create_hash_tables())
- return -1;
+ return -ENOMEM;
entry = proc_create("profile", S_IWUSR | S_IRUGO,
NULL, &proc_profile_operations);
if (!entry)
diff --git a/kernel/resource.c b/kernel/resource.c
index 414d6fc9131..f193d6e3ded 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -630,33 +630,34 @@ struct resource * __request_region(struct resource *parent,
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
- if (res) {
- res->name = name;
- res->start = start;
- res->end = start + n - 1;
- res->flags = IORESOURCE_BUSY;
+ if (!res)
+ return NULL;
- write_lock(&resource_lock);
+ res->name = name;
+ res->start = start;
+ res->end = start + n - 1;
+ res->flags = IORESOURCE_BUSY;
- for (;;) {
- struct resource *conflict;
+ write_lock(&resource_lock);
- conflict = __request_resource(parent, res);
- if (!conflict)
- break;
- if (conflict != parent) {
- parent = conflict;
- if (!(conflict->flags & IORESOURCE_BUSY))
- continue;
- }
+ for (;;) {
+ struct resource *conflict;
- /* Uhhuh, that didn't work out.. */
- kfree(res);
- res = NULL;
+ conflict = __request_resource(parent, res);
+ if (!conflict)
break;
+ if (conflict != parent) {
+ parent = conflict;
+ if (!(conflict->flags & IORESOURCE_BUSY))
+ continue;
}
- write_unlock(&resource_lock);
+
+ /* Uhhuh, that didn't work out.. */
+ kfree(res);
+ res = NULL;
+ break;
}
+ write_unlock(&resource_lock);
return res;
}
EXPORT_SYMBOL(__request_region);
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index cb838ee93a8..3953e4aed73 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -226,7 +226,7 @@ static void check_hung_uninterruptible_tasks(int this_cpu)
* If the system crashed already then all bets are off,
* do not report extra hung tasks:
*/
- if ((tainted & TAINT_DIE) || did_panic)
+ if (test_taint(TAINT_DIE) || did_panic)
return;
read_lock(&tasklist_lock);
diff --git a/kernel/sys.c b/kernel/sys.c
index 234d9454294..0bc8fa3c228 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1349,8 +1349,10 @@ asmlinkage long sys_sethostname(char __user *name, int len)
down_write(&uts_sem);
errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
- memcpy(utsname()->nodename, tmp, len);
- utsname()->nodename[len] = 0;
+ struct new_utsname *u = utsname();
+
+ memcpy(u->nodename, tmp, len);
+ memset(u->nodename + len, 0, sizeof(u->nodename) - len);
errno = 0;
}
up_write(&uts_sem);
@@ -1362,15 +1364,17 @@ asmlinkage long sys_sethostname(char __user *name, int len)
asmlinkage long sys_gethostname(char __user *name, int len)
{
int i, errno;
+ struct new_utsname *u;
if (len < 0)
return -EINVAL;
down_read(&uts_sem);
- i = 1 + strlen(utsname()->nodename);
+ u = utsname();
+ i = 1 + strlen(u->nodename);
if (i > len)
i = len;
errno = 0;
- if (copy_to_user(name, utsname()->nodename, i))
+ if (copy_to_user(name, u->nodename, i))
errno = -EFAULT;
up_read(&uts_sem);
return errno;
@@ -1395,8 +1399,10 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
down_write(&uts_sem);
errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
- memcpy(utsname()->domainname, tmp, len);
- utsname()->domainname[len] = 0;
+ struct new_utsname *u = utsname();
+
+ memcpy(u->domainname, tmp, len);
+ memset(u->domainname + len, 0, sizeof(u->domainname) - len);
errno = 0;
}
up_write(&uts_sem);
@@ -1450,14 +1456,22 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
return -EINVAL;
if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
return -EFAULT;
- if (new_rlim.rlim_cur > new_rlim.rlim_max)
- return -EINVAL;
old_rlim = current->signal->rlim + resource;
if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
!capable(CAP_SYS_RESOURCE))
return -EPERM;
- if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
- return -EPERM;
+
+ if (resource == RLIMIT_NOFILE) {
+ if (new_rlim.rlim_max == RLIM_INFINITY)
+ new_rlim.rlim_max = sysctl_nr_open;
+ if (new_rlim.rlim_cur == RLIM_INFINITY)
+ new_rlim.rlim_cur = sysctl_nr_open;
+ if (new_rlim.rlim_max > sysctl_nr_open)
+ return -EPERM;
+ }
+
+ if (new_rlim.rlim_cur > new_rlim.rlim_max)
+ return -EINVAL;
retval = security_task_setrlimit(resource, &new_rlim);
if (retval)
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 08d6e1bb99a..a77b27b11b0 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -125,6 +125,12 @@ cond_syscall(sys_vm86old);
cond_syscall(sys_vm86);
cond_syscall(compat_sys_ipc);
cond_syscall(compat_sys_sysctl);
+cond_syscall(sys_flock);
+cond_syscall(sys_io_setup);
+cond_syscall(sys_io_destroy);
+cond_syscall(sys_io_submit);
+cond_syscall(sys_io_cancel);
+cond_syscall(sys_io_getevents);
/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index c468c3c6dfc..617d41e4d6a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -96,7 +96,7 @@ static int sixty = 60;
static int neg_one = -1;
#endif
-#ifdef CONFIG_MMU
+#if defined(CONFIG_MMU) && defined(CONFIG_FILE_LOCKING)
static int two = 2;
#endif
@@ -149,7 +149,7 @@ extern int max_lock_depth;
#ifdef CONFIG_PROC_SYSCTL
static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
-static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp,
+static int proc_taint(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
@@ -379,10 +379,9 @@ static struct ctl_table kern_table[] = {
#ifdef CONFIG_PROC_SYSCTL
{
.procname = "tainted",
- .data = &tainted,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(long),
.mode = 0644,
- .proc_handler = &proc_dointvec_taint,
+ .proc_handler = &proc_taint,
},
#endif
#ifdef CONFIG_LATENCYTOP
@@ -1248,6 +1247,7 @@ static struct ctl_table fs_table[] = {
.extra1 = &minolduid,
.extra2 = &maxolduid,
},
+#ifdef CONFIG_FILE_LOCKING
{
.ctl_name = FS_LEASES,
.procname = "leases-enable",
@@ -1256,6 +1256,7 @@ static struct ctl_table fs_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#endif
#ifdef CONFIG_DNOTIFY
{
.ctl_name = FS_DIR_NOTIFY,
@@ -1267,6 +1268,7 @@ static struct ctl_table fs_table[] = {
},
#endif
#ifdef CONFIG_MMU
+#ifdef CONFIG_FILE_LOCKING
{
.ctl_name = FS_LEASE_TIME,
.procname = "lease-break-time",
@@ -1278,6 +1280,8 @@ static struct ctl_table fs_table[] = {
.extra1 = &zero,
.extra2 = &two,
},
+#endif
+#ifdef CONFIG_AIO
{
.procname = "aio-nr",
.data = &aio_nr,
@@ -1292,6 +1296,7 @@ static struct ctl_table fs_table[] = {
.mode = 0644,
.proc_handler = &proc_doulongvec_minmax,
},
+#endif /* CONFIG_AIO */
#ifdef CONFIG_INOTIFY_USER
{
.ctl_name = FS_INOTIFY,
@@ -1497,7 +1502,6 @@ void register_sysctl_root(struct ctl_table_root *root)
/* Perform the actual read/write of a sysctl table entry. */
static int do_sysctl_strategy(struct ctl_table_root *root,
struct ctl_table *table,
- int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -1511,8 +1515,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
return -EPERM;
if (table->strategy) {
- rc = table->strategy(table, name, nlen, oldval, oldlenp,
- newval, newlen);
+ rc = table->strategy(table, oldval, oldlenp, newval, newlen);
if (rc < 0)
return rc;
if (rc > 0)
@@ -1522,8 +1525,7 @@ static int do_sysctl_strategy(struct ctl_table_root *root,
/* If there is no strategy routine, or if the strategy returns
* zero, proceed with automatic r/w */
if (table->data && table->maxlen) {
- rc = sysctl_data(table, name, nlen, oldval, oldlenp,
- newval, newlen);
+ rc = sysctl_data(table, oldval, oldlenp, newval, newlen);
if (rc < 0)
return rc;
}
@@ -1555,7 +1557,7 @@ repeat:
table = table->child;
goto repeat;
}
- error = do_sysctl_strategy(root, table, name, nlen,
+ error = do_sysctl_strategy(root, table,
oldval, oldlenp,
newval, newlen);
return error;
@@ -2224,49 +2226,39 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp,
NULL,NULL);
}
-#define OP_SET 0
-#define OP_AND 1
-#define OP_OR 2
-
-static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
- int *valp,
- int write, void *data)
-{
- int op = *(int *)data;
- if (write) {
- int val = *negp ? -*lvalp : *lvalp;
- switch(op) {
- case OP_SET: *valp = val; break;
- case OP_AND: *valp &= val; break;
- case OP_OR: *valp |= val; break;
- }
- } else {
- int val = *valp;
- if (val < 0) {
- *negp = -1;
- *lvalp = (unsigned long)-val;
- } else {
- *negp = 0;
- *lvalp = (unsigned long)val;
- }
- }
- return 0;
-}
-
/*
- * Taint values can only be increased
+ * Taint values can only be increased
+ * This means we can safely use a temporary.
*/
-static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp,
+static int proc_taint(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
- int op;
+ struct ctl_table t;
+ unsigned long tmptaint = get_taint();
+ int err;
if (write && !capable(CAP_SYS_ADMIN))
return -EPERM;
- op = OP_OR;
- return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
- do_proc_dointvec_bset_conv,&op);
+ t = *table;
+ t.data = &tmptaint;
+ err = proc_doulongvec_minmax(&t, write, filp, buffer, lenp, ppos);
+ if (err < 0)
+ return err;
+
+ if (write) {
+ /*
+ * Poor man's atomic or. Not worth adding a primitive
+ * to everyone's atomic.h for this
+ */
+ int i;
+ for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) {
+ if ((tmptaint >> i) & 1)
+ add_taint(i);
+ }
+ }
+
+ return err;
}
struct do_proc_dointvec_minmax_conv_param {
@@ -2714,7 +2706,7 @@ int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write,
*/
/* The generic sysctl data routine (used if no strategy routine supplied) */
-int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_data(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -2748,7 +2740,7 @@ int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
}
/* The generic string strategy routine: */
-int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_string(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -2794,7 +2786,7 @@ int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
* are between the minimum and maximum values given in the arrays
* table->extra1 and table->extra2, respectively.
*/
-int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_intvec(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -2830,7 +2822,7 @@ int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
}
/* Strategy function to convert jiffies to seconds */
-int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_jiffies(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -2864,7 +2856,7 @@ int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
}
/* Strategy function to convert jiffies to seconds */
-int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_ms_jiffies(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -2919,35 +2911,35 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
return error;
}
-int sysctl_data(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_data(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
return -ENOSYS;
}
-int sysctl_string(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_string(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
return -ENOSYS;
}
-int sysctl_intvec(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_intvec(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
return -ENOSYS;
}
-int sysctl_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_jiffies(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
return -ENOSYS;
}
-int sysctl_ms_jiffies(struct ctl_table *table, int __user *name, int nlen,
+int sysctl_ms_jiffies(struct ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig
index 8d53106a0a9..95ed42951e0 100644
--- a/kernel/time/Kconfig
+++ b/kernel/time/Kconfig
@@ -3,7 +3,6 @@
#
config TICK_ONESHOT
bool
- default n
config NO_HZ
bool "Tickless System (Dynamic Ticks)"
diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c
index 4ab9659d269..3b34b354593 100644
--- a/kernel/utsname_sysctl.c
+++ b/kernel/utsname_sysctl.c
@@ -60,7 +60,7 @@ static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
#ifdef CONFIG_SYSCTL_SYSCALL
/* The generic string strategy routine: */
-static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
+static int sysctl_uts_string(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -69,8 +69,7 @@ static int sysctl_uts_string(ctl_table *table, int __user *name, int nlen,
write = newval && newlen;
memcpy(&uts_table, table, sizeof(uts_table));
uts_table.data = get_uts(table, write);
- r = sysctl_string(&uts_table, name, nlen,
- oldval, oldlenp, newval, newlen);
+ r = sysctl_string(&uts_table, oldval, oldlenp, newval, newlen);
put_uts(table, write, uts_table.data);
return r;
}
diff --git a/kernel/wait.c b/kernel/wait.c
index c275c56cf2d..cd87131f2fc 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -72,12 +72,7 @@ prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state)
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
__add_wait_queue(q, wait);
- /*
- * don't alter the task state if this is just going to
- * queue an async wait queue callback
- */
- if (is_sync_wait(wait))
- set_current_state(state);
+ set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(prepare_to_wait);
@@ -91,12 +86,7 @@ prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state)
spin_lock_irqsave(&q->lock, flags);
if (list_empty(&wait->task_list))
__add_wait_queue_tail(q, wait);
- /*
- * don't alter the task state if this is just going to
- * queue an async wait queue callback
- */
- if (is_sync_wait(wait))
- set_current_state(state);
+ set_current_state(state);
spin_unlock_irqrestore(&q->lock, flags);
}
EXPORT_SYMBOL(prepare_to_wait_exclusive);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 4048e92aa04..714afad4653 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -9,7 +9,7 @@
* Derived from the taskqueue/keventd code by:
*
* David Woodhouse <dwmw2@infradead.org>
- * Andrew Morton <andrewm@uow.edu.au>
+ * Andrew Morton
* Kai Petzke <wpp@marie.physik.tu-berlin.de>
* Theodore Ts'o <tytso@mit.edu>
*
diff --git a/lib/Kconfig b/lib/Kconfig
index c7ad7a5b353..85cf7ea978a 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -8,10 +8,10 @@ config BITREVERSE
tristate
config GENERIC_FIND_FIRST_BIT
- def_bool n
+ bool
config GENERIC_FIND_NEXT_BIT
- def_bool n
+ bool
config CRC_CCITT
tristate "CRC-CCITT functions"
diff --git a/lib/iommu-helper.c b/lib/iommu-helper.c
index 5d90074dca7..75dbda03f4f 100644
--- a/lib/iommu-helper.c
+++ b/lib/iommu-helper.c
@@ -79,3 +79,12 @@ void iommu_area_free(unsigned long *map, unsigned long start, unsigned int nr)
}
}
EXPORT_SYMBOL(iommu_area_free);
+
+unsigned long iommu_num_pages(unsigned long addr, unsigned long len,
+ unsigned long io_page_size)
+{
+ unsigned long size = (addr & (io_page_size - 1)) + len;
+
+ return DIV_ROUND_UP(size, io_page_size);
+}
+EXPORT_SYMBOL(iommu_num_pages);
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index c399bc1093c..4c6674a41ed 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -565,6 +565,10 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field
* @fmt: The format string to use
* @args: Arguments for the format string
*
+ * This function follows C99 vsnprintf, but has some extensions:
+ * %pS output the name of a text symbol
+ * %pF output the name of a function pointer
+ *
* The return value is the number of characters which would
* be generated for the given input, excluding the trailing
* '\0', as per ISO C99. If you want to have the exact
@@ -806,6 +810,8 @@ EXPORT_SYMBOL(vsnprintf);
*
* Call this function if you are already dealing with a va_list.
* You probably want scnprintf() instead.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
*/
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
{
@@ -828,6 +834,8 @@ EXPORT_SYMBOL(vscnprintf);
* generated for the given input, excluding the trailing null,
* as per ISO C99. If the return is greater than or equal to
* @size, the resulting string is truncated.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
*/
int snprintf(char * buf, size_t size, const char *fmt, ...)
{
@@ -877,6 +885,8 @@ EXPORT_SYMBOL(scnprintf);
*
* Call this function if you are already dealing with a va_list.
* You probably want sprintf() instead.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
*/
int vsprintf(char *buf, const char *fmt, va_list args)
{
@@ -894,6 +904,8 @@ EXPORT_SYMBOL(vsprintf);
* The function returns the number of characters written
* into @buf. Use snprintf() or scnprintf() in order to avoid
* buffer overflows.
+ *
+ * See the vsnprintf() documentation for format string extensions over C99.
*/
int sprintf(char * buf, const char *fmt, ...)
{
diff --git a/mm/Kconfig b/mm/Kconfig
index 0bd9c2dbb2a..5585f129359 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -101,7 +101,7 @@ config HAVE_MEMORY_PRESENT
# with gcc 3.4 and later.
#
config SPARSEMEM_STATIC
- def_bool n
+ bool
#
# Architecture platforms which require a two level mem_section in SPARSEMEM
@@ -113,7 +113,7 @@ config SPARSEMEM_EXTREME
depends on SPARSEMEM && !SPARSEMEM_STATIC
config SPARSEMEM_VMEMMAP_ENABLE
- def_bool n
+ bool
config SPARSEMEM_VMEMMAP
bool "Sparse Memory virtual memmap"
diff --git a/mm/bootmem.c b/mm/bootmem.c
index ad8eec6e44a..ac5a891f142 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -48,7 +48,7 @@ early_param("bootmem_debug", bootmem_debug_setup);
if (unlikely(bootmem_debug)) \
printk(KERN_INFO \
"bootmem::%s " fmt, \
- __FUNCTION__, ## args); \
+ __func__, ## args); \
})
static unsigned long __init bootmap_bytes(unsigned long pages)
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 343cfdfebd9..a1da969bd98 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Linus Torvalds
*
- * 11Jan2003 akpm@digeo.com
+ * 11Jan2003 Andrew Morton
* Initial version.
*/
diff --git a/mm/filemap.c b/mm/filemap.c
index 876bc595d0f..bf8f9c0c7a8 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1186,8 +1186,7 @@ out:
ra->prev_pos |= prev_offset;
*ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
- if (filp)
- file_accessed(filp);
+ file_accessed(filp);
}
int file_read_actor(read_descriptor_t *desc, struct page *page,
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 67a71191136..38633864a93 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2008,7 +2008,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
entry = huge_ptep_get(ptep);
if (huge_pte_none(entry)) {
ret = hugetlb_no_page(mm, vma, address, ptep, write_access);
- goto out_unlock;
+ goto out_mutex;
}
ret = 0;
@@ -2024,7 +2024,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (write_access && !pte_write(entry)) {
if (vma_needs_reservation(h, vma, address) < 0) {
ret = VM_FAULT_OOM;
- goto out_unlock;
+ goto out_mutex;
}
if (!(vma->vm_flags & VM_SHARED))
@@ -2034,10 +2034,23 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
spin_lock(&mm->page_table_lock);
/* Check for a racing update before calling hugetlb_cow */
- if (likely(pte_same(entry, huge_ptep_get(ptep))))
- if (write_access && !pte_write(entry))
+ if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
+ goto out_page_table_lock;
+
+
+ if (write_access) {
+ if (!pte_write(entry)) {
ret = hugetlb_cow(mm, vma, address, ptep, entry,
pagecache_page);
+ goto out_page_table_lock;
+ }
+ entry = pte_mkdirty(entry);
+ }
+ entry = pte_mkyoung(entry);
+ if (huge_ptep_set_access_flags(vma, address, ptep, entry, write_access))
+ update_mmu_cache(vma, address, entry);
+
+out_page_table_lock:
spin_unlock(&mm->page_table_lock);
if (pagecache_page) {
@@ -2045,7 +2058,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
put_page(pagecache_page);
}
-out_unlock:
+out_mutex:
mutex_unlock(&hugetlb_instantiation_mutex);
return ret;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 24de8b65fdb..c130a137c12 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -7,7 +7,7 @@
* Contains functions related to writing back dirty pages at the
* address_space level.
*
- * 10Apr2002 akpm@zip.com.au
+ * 10Apr2002 Andrew Morton
* Initial version
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 27b8681139f..9eb9eb92828 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3952,7 +3952,7 @@ static void check_for_regular_memory(pg_data_t *pgdat)
void __init free_area_init_nodes(unsigned long *max_zone_pfn)
{
unsigned long nid;
- enum zone_type i;
+ int i;
/* Sort early_node_map as initialisation assumes it is sorted */
sort_node_map();
diff --git a/mm/pdflush.c b/mm/pdflush.c
index 0cbe0c60c6b..a0a14c4d507 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Linus Torvalds.
*
- * 09Apr2002 akpm@zip.com.au
+ * 09Apr2002 Andrew Morton
* Initial version
* 29Feb2004 kaos@sgi.com
* Move worker thread creation to kthread to avoid chewing
diff --git a/mm/readahead.c b/mm/readahead.c
index 77e8ddf945e..6cbd9a72fde 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Linus Torvalds
*
- * 09Apr2002 akpm@zip.com.au
+ * 09Apr2002 Andrew Morton
* Initial version.
*/
diff --git a/mm/truncate.c b/mm/truncate.c
index 6650c1d878b..e83e4b114ef 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2002, Linus Torvalds
*
- * 10Sep2002 akpm@zip.com.au
+ * 10Sep2002 Andrew Morton
* Initial version.
*/
diff --git a/net/802/psnap.c b/net/802/psnap.c
index b3cfe5a14fc..70980baeb68 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -1,7 +1,7 @@
/*
* SNAP data link layer. Derived from 802.2
*
- * Alan Cox <Alan.Cox@linux.org>,
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>,
* from the 802.2 layer by Greg Page.
* Merged in additions from Greg Page's psnap.c.
*
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 0c850427a85..d3134e7e6ee 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -2,7 +2,7 @@
* DDP: An implementation of the AppleTalk DDP protocol for
* Ethernet 'ELAP'.
*
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* With more than a little assistance from
*
@@ -1934,6 +1934,6 @@ static void __exit atalk_exit(void)
module_exit(atalk_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alan Cox <Alan.Cox@linux.org>");
+MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
MODULE_DESCRIPTION("AppleTalk 0.20\n");
MODULE_ALIAS_NETPROTO(PF_APPLETALK);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index 96434d774c8..acdeab3d980 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -578,7 +578,7 @@ static int hidp_session(void *arg)
if (session->hid) {
if (session->hid->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(session->hid);
- hid_free_device(session->hid);
+ hid_destroy_device(session->hid);
}
/* Wakeup user-space polling for socket errors */
@@ -623,9 +623,15 @@ static struct device *hidp_get_device(struct hidp_session *session)
static int hidp_setup_input(struct hidp_session *session,
struct hidp_connadd_req *req)
{
- struct input_dev *input = session->input;
+ struct input_dev *input;
int i;
+ input = input_allocate_device();
+ if (!input)
+ return -ENOMEM;
+
+ session->input = input;
+
input_set_drvdata(input, session);
input->name = "Bluetooth HID Boot Protocol Device";
@@ -677,67 +683,114 @@ static void hidp_close(struct hid_device *hid)
{
}
-static const struct {
- __u16 idVendor;
- __u16 idProduct;
- unsigned quirks;
-} hidp_blacklist[] = {
- /* Apple wireless Mighty Mouse */
- { 0x05ac, 0x030c, HID_QUIRK_MIGHTYMOUSE | HID_QUIRK_INVERT_HWHEEL },
+static int hidp_parse(struct hid_device *hid)
+{
+ struct hidp_session *session = hid->driver_data;
+ struct hidp_connadd_req *req = session->req;
+ unsigned char *buf;
+ int ret;
- { } /* Terminating entry */
-};
+ buf = kmalloc(req->rd_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (copy_from_user(buf, req->rd_data, req->rd_size)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+
+ ret = hid_parse_report(session->hid, buf, req->rd_size);
+
+ kfree(buf);
+
+ if (ret)
+ return ret;
+
+ session->req = NULL;
+
+ return 0;
+}
+
+static int hidp_start(struct hid_device *hid)
+{
+ struct hidp_session *session = hid->driver_data;
+ struct hid_report *report;
-static void hidp_setup_quirks(struct hid_device *hid)
+ list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
+ report_list, list)
+ hidp_send_report(session, report);
+
+ list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
+ report_list, list)
+ hidp_send_report(session, report);
+
+ return 0;
+}
+
+static void hidp_stop(struct hid_device *hid)
{
- unsigned int n;
+ struct hidp_session *session = hid->driver_data;
+
+ skb_queue_purge(&session->ctrl_transmit);
+ skb_queue_purge(&session->intr_transmit);
- for (n = 0; hidp_blacklist[n].idVendor; n++)
- if (hidp_blacklist[n].idVendor == le16_to_cpu(hid->vendor) &&
- hidp_blacklist[n].idProduct == le16_to_cpu(hid->product))
- hid->quirks = hidp_blacklist[n].quirks;
+ if (hid->claimed & HID_CLAIMED_INPUT)
+ hidinput_disconnect(hid);
+ hid->claimed = 0;
}
-static void hidp_setup_hid(struct hidp_session *session,
+static struct hid_ll_driver hidp_hid_driver = {
+ .parse = hidp_parse,
+ .start = hidp_start,
+ .stop = hidp_stop,
+ .open = hidp_open,
+ .close = hidp_close,
+ .hidinput_input_event = hidp_hidinput_event,
+};
+
+static int hidp_setup_hid(struct hidp_session *session,
struct hidp_connadd_req *req)
{
- struct hid_device *hid = session->hid;
- struct hid_report *report;
+ struct hid_device *hid;
bdaddr_t src, dst;
+ int ret;
- baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
- baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
+ hid = hid_allocate_device();
+ if (IS_ERR(hid)) {
+ ret = PTR_ERR(session->hid);
+ goto err;
+ }
+ session->hid = hid;
+ session->req = req;
hid->driver_data = session;
- hid->country = req->country;
+ baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
+ baswap(&dst, &bt_sk(session->ctrl_sock->sk)->dst);
hid->bus = BUS_BLUETOOTH;
hid->vendor = req->vendor;
hid->product = req->product;
hid->version = req->version;
+ hid->country = req->country;
strncpy(hid->name, req->name, 128);
strncpy(hid->phys, batostr(&src), 64);
strncpy(hid->uniq, batostr(&dst), 64);
- hid->dev = hidp_get_device(session);
-
- hid->hid_open = hidp_open;
- hid->hid_close = hidp_close;
-
- hid->hidinput_input_event = hidp_hidinput_event;
+ hid->dev.parent = hidp_get_device(session);
+ hid->ll_driver = &hidp_hid_driver;
- hidp_setup_quirks(hid);
+ ret = hid_add_device(hid);
+ if (ret)
+ goto err_hid;
- list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list)
- hidp_send_report(session, report);
-
- list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
- hidp_send_report(session, report);
-
- if (hidinput_connect(hid) == 0)
- hid->claimed |= HID_CLAIMED_INPUT;
+ return 0;
+err_hid:
+ hid_destroy_device(hid);
+ session->hid = NULL;
+err:
+ return ret;
}
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
@@ -757,38 +810,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
- if (req->rd_size > 0) {
- unsigned char *buf = kmalloc(req->rd_size, GFP_KERNEL);
-
- if (!buf) {
- kfree(session);
- return -ENOMEM;
- }
-
- if (copy_from_user(buf, req->rd_data, req->rd_size)) {
- kfree(buf);
- kfree(session);
- return -EFAULT;
- }
-
- session->hid = hid_parse_report(buf, req->rd_size);
-
- kfree(buf);
-
- if (!session->hid) {
- kfree(session);
- return -EINVAL;
- }
- }
-
- if (!session->hid) {
- session->input = input_allocate_device();
- if (!session->input) {
- kfree(session);
- return -ENOMEM;
- }
- }
-
down_write(&hidp_session_sem);
s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
@@ -816,15 +837,18 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
session->idle_to = req->idle_to;
- if (session->input) {
+ if (req->rd_size > 0) {
+ err = hidp_setup_hid(session, req);
+ if (err && err != -ENODEV)
+ goto err_skb;
+ }
+
+ if (!session->hid) {
err = hidp_setup_input(session, req);
if (err < 0)
- goto failed;
+ goto err_skb;
}
- if (session->hid)
- hidp_setup_hid(session, req);
-
__hidp_link_session(session);
hidp_set_timer(session);
@@ -850,17 +874,16 @@ unlink:
__hidp_unlink_session(session);
- if (session->input) {
+ if (session->input)
input_unregister_device(session->input);
- session->input = NULL; /* don't try to free it here */
- }
-
+ if (session->hid)
+ hid_destroy_device(session->hid);
+err_skb:
+ skb_queue_purge(&session->ctrl_transmit);
+ skb_queue_purge(&session->intr_transmit);
failed:
up_write(&hidp_session_sem);
- if (session->hid)
- hid_free_device(session->hid);
-
input_free_device(session->input);
kfree(session);
return err;
@@ -950,18 +973,43 @@ int hidp_get_conninfo(struct hidp_conninfo *ci)
return err;
}
+static const struct hid_device_id hidp_table[] = {
+ { HID_BLUETOOTH_DEVICE(HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+
+static struct hid_driver hidp_driver = {
+ .name = "generic-bluetooth",
+ .id_table = hidp_table,
+};
+
static int __init hidp_init(void)
{
+ int ret;
+
l2cap_load();
BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION);
- return hidp_init_sockets();
+ ret = hid_register_driver(&hidp_driver);
+ if (ret)
+ goto err;
+
+ ret = hidp_init_sockets();
+ if (ret)
+ goto err_drv;
+
+ return 0;
+err_drv:
+ hid_unregister_driver(&hidp_driver);
+err:
+ return ret;
}
static void __exit hidp_exit(void)
{
hidp_cleanup_sockets();
+ hid_unregister_driver(&hidp_driver);
}
module_init(hidp_init);
diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h
index 343fb0566b3..e503c89057a 100644
--- a/net/bluetooth/hidp/hidp.h
+++ b/net/bluetooth/hidp/hidp.h
@@ -151,6 +151,8 @@ struct hidp_session {
struct sk_buff_head ctrl_transmit;
struct sk_buff_head intr_transmit;
+
+ struct hidp_connadd_req *req;
};
static inline void hidp_schedule(struct hidp_session *session)
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 52f577a0f54..ee631843c2f 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -9,7 +9,7 @@
* identical recvmsg() code. So we share it here. The poll was
* shared before but buried in udp.c so I moved it.
*
- * Authors: Alan Cox <alan@redhat.com>. (datagram_poll() from old
+ * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>. (datagram_poll() from old
* udp.c code)
*
* Fixes:
diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
index 5402b3b38e0..9e2fa39f22a 100644
--- a/net/core/dev_mcast.c
+++ b/net/core/dev_mcast.c
@@ -6,7 +6,7 @@
* Richard Underwood <richard@wuzz.demon.co.uk>
*
* Stir fried together from the IP multicast and CAP patches above
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Fixes:
* Alan Cox : Update the device on a real delete
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index a756847e381..99f656d35b4 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2474,7 +2474,7 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
if (ret < 0) {
printk(KERN_ERR "Error expanding "
"ipsec packet %d\n",ret);
- return 0;
+ goto err;
}
}
@@ -2484,8 +2484,7 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
if (ret) {
printk(KERN_ERR "Error creating ipsec "
"packet %d\n",ret);
- kfree_skb(skb);
- return 0;
+ goto err;
}
/* restore ll */
eth = (__u8 *) skb_push(skb, ETH_HLEN);
@@ -2494,6 +2493,9 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
}
}
return 1;
+err:
+ kfree_skb(skb);
+ return 0;
}
#endif
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 7f7bb1a636d..4e22e3a3535 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1,7 +1,7 @@
/*
* Routines having to do with the 'struct sk_buff' memory handlers.
*
- * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>
* Florian La Roche <rzsfl@rz.uni-sb.de>
*
* Fixes:
diff --git a/net/core/stream.c b/net/core/stream.c
index a6b3437ff08..8727cead64a 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -9,7 +9,7 @@
*
* Authors: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* (from old tcp.c code)
- * Alan Cox <alan@redhat.com> (Borrowed comments 8-))
+ * Alan Cox <alan@lxorguk.ukuu.org.uk> (Borrowed comments 8-))
*/
#include <linux/module.h>
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 2f0ac3c3eb7..96f9fcef295 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -166,7 +166,7 @@ static int max_priority[] = { 127 }; /* From DECnet spec */
static int dn_forwarding_proc(ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+static int dn_forwarding_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
@@ -318,7 +318,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
#endif
}
-static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+static int dn_forwarding_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c
index 228067c571b..36400b26689 100644
--- a/net/decnet/sysctl_net_decnet.c
+++ b/net/decnet/sysctl_net_decnet.c
@@ -132,7 +132,7 @@ static int parse_addr(__le16 *addr, char *str)
}
-static int dn_node_address_strategy(ctl_table *table, int __user *name, int nlen,
+static int dn_node_address_strategy(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -217,7 +217,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
}
-static int dn_def_dev_strategy(ctl_table *table, int __user *name, int nlen,
+static int dn_def_dev_strategy(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index cdce4c6c672..49211b35725 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -1,7 +1,7 @@
menuconfig NET_DSA
bool "Distributed Switch Architecture support"
default n
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && !S390
select PHYLIB
---help---
This allows you to use hardware switch chips that use
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index b12dae2b0b2..5154e729cf1 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1283,7 +1283,7 @@ static int devinet_conf_proc(ctl_table *ctl, int write,
return ret;
}
-static int devinet_conf_sysctl(ctl_table *table, int __user *name, int nlen,
+static int devinet_conf_sysctl(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -1379,12 +1379,11 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
return ret;
}
-int ipv4_doint_and_flush_strategy(ctl_table *table, int __user *name, int nlen,
+int ipv4_doint_and_flush_strategy(ctl_table *table,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
- int ret = devinet_conf_sysctl(table, name, nlen, oldval, oldlenp,
- newval, newlen);
+ int ret = devinet_conf_sysctl(table, oldval, oldlenp, newval, newlen);
struct net *net = table->extra2;
if (ret == 1)
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 55c355e6323..72b2de76f1c 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -1,7 +1,7 @@
/*
* NET3: Implementation of the ICMP protocol layer.
*
- * Alan Cox, <alan@redhat.com>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 7f9e337e390..a0d86455c53 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -9,7 +9,7 @@
* seems to fall out with gcc 2.6.2.
*
* Authors:
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 2152d222b95..e4f81f54bef 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -6,7 +6,7 @@
* The IP fragmentation functionality.
*
* Authors: Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
- * Alan Cox <Alan.Cox@linux.org>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>
*
* Fixes:
* Alan Cox : Split from ip.c , see ip_input.c for history.
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index e0bed56c51f..861978a4f1a 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -8,7 +8,7 @@
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
- * Alan Cox, <Alan.Cox@linux.org>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Richard Underwood
* Stefan Becker, <stefanb@yello.ping.de>
* Jorge Cwik, <jorge@laser.satlink.net>
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 4c6d2caf920..29609d29df7 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -41,7 +41,7 @@
Made the tunnels use dev->name not tunnel: when error reporting.
Added tx_dropped stat
- -Alan Cox (Alan.Cox@linux.org) 21 March 95
+ -Alan Cox (alan@lxorguk.ukuu.org.uk) 21 March 95
Reworked:
Changed to tunnel to destination gateway in addition to the
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index c519b8d30ee..b42e082cc17 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -1,7 +1,7 @@
/*
* IP multicast routing support for mrouted 3.6/3.8
*
- * (c) 1995 Alan Cox, <alan@redhat.com>
+ * (c) 1995 Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Linux Consultancy and Custom Driver Development
*
* This program is free software; you can redistribute it and/or
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index a6d7c584f53..942be04e795 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2908,8 +2908,6 @@ static int ipv4_sysctl_rtcache_flush(ctl_table *__ctl, int write,
}
static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
- int __user *name,
- int nlen,
void __user *oldval,
size_t __user *oldlenp,
void __user *newval,
@@ -2972,16 +2970,13 @@ static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
}
static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
- int __user *name,
- int nlen,
void __user *oldval,
size_t __user *oldlenp,
void __user *newval,
size_t newlen)
{
int old = ip_rt_secret_interval;
- int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval,
- newlen);
+ int ret = sysctl_jiffies(table, oldval, oldlenp, newval, newlen);
rt_secret_reschedule(old);
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 276d047fb85..1bb10df8ce7 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -64,8 +64,8 @@ static int ipv4_local_port_range(ctl_table *table, int write, struct file *filp,
}
/* Validate changes from sysctl interface. */
-static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
- int nlen, void __user *oldval,
+static int ipv4_sysctl_local_port_range(ctl_table *table,
+ void __user *oldval,
size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -80,7 +80,7 @@ static int ipv4_sysctl_local_port_range(ctl_table *table, int __user *name,
};
inet_get_local_port_range(range, range + 1);
- ret = sysctl_intvec(&tmp, name, nlen, oldval, oldlenp, newval, newlen);
+ ret = sysctl_intvec(&tmp, oldval, oldlenp, newval, newlen);
if (ret == 0 && newval && newlen) {
if (range[1] < range[0])
ret = -EINVAL;
@@ -109,8 +109,8 @@ static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file *
return ret;
}
-static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
- int nlen, void __user *oldval,
+static int sysctl_tcp_congestion_control(ctl_table *table,
+ void __user *oldval,
size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -122,7 +122,7 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
int ret;
tcp_get_default_congestion_control(val);
- ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
+ ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
if (ret == 1 && newval && newlen)
ret = tcp_set_default_congestion_control(val);
return ret;
@@ -165,8 +165,8 @@ static int proc_allowed_congestion_control(ctl_table *ctl,
return ret;
}
-static int strategy_allowed_congestion_control(ctl_table *table, int __user *name,
- int nlen, void __user *oldval,
+static int strategy_allowed_congestion_control(ctl_table *table,
+ void __user *oldval,
size_t __user *oldlenp,
void __user *newval,
size_t newlen)
@@ -179,7 +179,7 @@ static int strategy_allowed_congestion_control(ctl_table *table, int __user *nam
return -ENOMEM;
tcp_get_available_congestion_control(tbl.data, tbl.maxlen);
- ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen);
+ ret = sysctl_string(&tbl, oldval, oldlenp, newval, newlen);
if (ret == 1 && newval && newlen)
ret = tcp_set_allowed_congestion_control(tbl.data);
kfree(tbl.data);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index eacf4cfef14..2095abc3cab 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -8,7 +8,7 @@
* Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- * Alan Cox, <Alan.Cox@linux.org>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
* Hirokazu Takahashi, <taka@valinux.co.jp>
*
* Fixes:
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 7b6a584b62d..eea9542728c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3982,7 +3982,6 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
}
static int addrconf_sysctl_forward_strategy(ctl_table *table,
- int __user *name, int nlen,
void __user *oldval,
size_t __user *oldlenp,
void __user *newval, size_t newlen)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 050e14b7f70..01edac88851 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -834,7 +834,7 @@ static void __net_exit ipv6_cleanup_mibs(struct net *net)
snmp_mib_free((void **)net->mib.icmpv6msg_statistics);
}
-static int inet6_net_init(struct net *net)
+static int __net_init inet6_net_init(struct net *net)
{
int err = 0;
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 840b15780a3..7f39e9b3645 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -1730,9 +1730,8 @@ int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, struct file * f
return ret;
}
-int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
- int nlen, void __user *oldval,
- size_t __user *oldlenp,
+int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl,
+ void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
struct net_device *dev = ctl->extra1;
@@ -1745,13 +1744,11 @@ int ndisc_ifinfo_sysctl_strategy(ctl_table *ctl, int __user *name,
switch (ctl->ctl_name) {
case NET_NEIGH_REACHABLE_TIME:
- ret = sysctl_jiffies(ctl, name, nlen,
- oldval, oldlenp, newval, newlen);
+ ret = sysctl_jiffies(ctl, oldval, oldlenp, newval, newlen);
break;
case NET_NEIGH_RETRANS_TIME_MS:
case NET_NEIGH_REACHABLE_TIME_MS:
- ret = sysctl_ms_jiffies(ctl, name, nlen,
- oldval, oldlenp, newval, newlen);
+ ret = sysctl_ms_jiffies(ctl, oldval, oldlenp, newval, newlen);
break;
default:
ret = 0;
diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c
index 03591d37b9c..b92df5c1dfc 100644
--- a/net/netfilter/nf_conntrack_acct.c
+++ b/net/netfilter/nf_conntrack_acct.c
@@ -115,7 +115,7 @@ int nf_conntrack_acct_init(struct net *net)
if (net_eq(net, &init_net)) {
#ifdef CONFIG_NF_CT_ACCT
- printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Plase use\n");
+ printk(KERN_WARNING "CONFIG_NF_CT_ACCT is deprecated and will be removed soon. Please use\n");
printk(KERN_WARNING "nf_conntrack.acct=1 kernel paramater, acct=1 nf_conntrack module option or\n");
printk(KERN_WARNING "sysctl net.netfilter.nf_conntrack_acct=1 to enable it.\n");
#endif
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index b0eacc0007c..2fd8afac5f7 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1,7 +1,7 @@
/*
* NETLINK Kernel-user communication protocol.
*
- * Authors: Alan Cox <alan@redhat.com>
+ * Authors: Alan Cox <alan@lxorguk.ukuu.org.uk>
* Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
*
* This program is free software; you can redistribute it and/or
diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c
index e5b69556bb5..21124ec0a73 100644
--- a/net/rfkill/rfkill-input.c
+++ b/net/rfkill/rfkill-input.c
@@ -16,6 +16,7 @@
#include <linux/workqueue.h>
#include <linux/init.h>
#include <linux/rfkill.h>
+#include <linux/sched.h>
#include "rfkill-input.h"
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 76739e928d0..da0789fa1b8 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -174,7 +174,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
clnt->cl_procinfo = version->procs;
clnt->cl_maxproc = version->nrprocs;
clnt->cl_protname = program->name;
- clnt->cl_prog = program->number;
+ clnt->cl_prog = args->prognumber ? : program->number;
clnt->cl_vers = version->number;
clnt->cl_stats = program->stats;
clnt->cl_metrics = rpc_alloc_iostats(clnt);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 24db2b4d12d..34abc91058d 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -20,6 +20,7 @@
#include <linux/in6.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <net/ipv6.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
@@ -176,13 +177,12 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
}
static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
- u32 version, struct rpc_message *msg,
- int *result)
+ u32 version, struct rpc_message *msg)
{
struct rpc_clnt *rpcb_clnt;
- int error = 0;
+ int result, error = 0;
- *result = 0;
+ msg->rpc_resp = &result;
rpcb_clnt = rpcb_create_local(addr, addrlen, version);
if (!IS_ERR(rpcb_clnt)) {
@@ -191,12 +191,15 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
} else
error = PTR_ERR(rpcb_clnt);
- if (error < 0)
+ if (error < 0) {
printk(KERN_WARNING "RPC: failed to contact local rpcbind "
"server (errno %d).\n", -error);
- dprintk("RPC: registration status %d/%d\n", error, *result);
+ return error;
+ }
- return error;
+ if (!result)
+ return -EACCES;
+ return 0;
}
/**
@@ -205,7 +208,11 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* @vers: RPC version number to bind
* @prot: transport protocol to register
* @port: port value to register
- * @okay: OUT: result code
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success. Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
*
* RPC services invoke this function to advertise their contact
* information via the system's rpcbind daemon. RPC services
@@ -217,15 +224,6 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* all registered transports for [program, version] from the local
* rpcbind database.
*
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received. The rpcbind daemon's
- * boolean result code is stored in *okay.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
* This function uses rpcbind protocol version 2 to contact the
* local rpcbind daemon.
*
@@ -236,7 +234,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
* addresses).
*/
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
{
struct rpcbind_args map = {
.r_prog = prog,
@@ -246,7 +244,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
};
struct rpc_message msg = {
.rpc_argp = &map,
- .rpc_resp = okay,
};
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
@@ -259,7 +256,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
sizeof(rpcb_inaddr_loopback),
- RPCBVERS_2, &msg, okay);
+ RPCBVERS_2, &msg);
}
/*
@@ -290,7 +287,7 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
sizeof(rpcb_inaddr_loopback),
- RPCBVERS_4, msg, msg->rpc_resp);
+ RPCBVERS_4, msg);
}
/*
@@ -304,10 +301,13 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
char buf[64];
/* Construct AF_INET6 universal address */
- snprintf(buf, sizeof(buf),
- NIP6_FMT".%u.%u",
- NIP6(address_to_register->sin6_addr),
- port >> 8, port & 0xff);
+ if (ipv6_addr_any(&address_to_register->sin6_addr))
+ snprintf(buf, sizeof(buf), "::.%u.%u",
+ port >> 8, port & 0xff);
+ else
+ snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u",
+ NIP6(address_to_register->sin6_addr),
+ port >> 8, port & 0xff);
map->r_addr = buf;
dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with "
@@ -321,7 +321,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
sizeof(rpcb_in6addr_loopback),
- RPCBVERS_4, msg, msg->rpc_resp);
+ RPCBVERS_4, msg);
}
/**
@@ -330,7 +330,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* @version: RPC version number of service to (un)register
* @address: address family, IP address, and port to (un)register
* @netid: netid of transport protocol to (un)register
- * @result: result code from rpcbind RPC call
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success. Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
*
* RPC services invoke this function to advertise their contact
* information via the system's rpcbind daemon. RPC services
@@ -342,15 +346,6 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* to zero. Callers pass a netid of "" to unregister all
* transport netids associated with [program, version, address].
*
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received. The rpcbind daemon's
- * result code is stored in *result.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
* This function uses rpcbind protocol version 4 to contact the
* local rpcbind daemon. The local rpcbind daemon must support
* version 4 of the rpcbind protocol in order for these functions
@@ -372,8 +367,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* advertises the service on all IPv4 and IPv6 addresses.
*/
int rpcb_v4_register(const u32 program, const u32 version,
- const struct sockaddr *address, const char *netid,
- int *result)
+ const struct sockaddr *address, const char *netid)
{
struct rpcbind_args map = {
.r_prog = program,
@@ -383,11 +377,8 @@ int rpcb_v4_register(const u32 program, const u32 version,
};
struct rpc_message msg = {
.rpc_argp = &map,
- .rpc_resp = result,
};
- *result = 0;
-
switch (address->sa_family) {
case AF_INET:
return rpcb_register_netid4((struct sockaddr_in *)address,
@@ -633,7 +624,7 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)
static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
struct rpcbind_args *rpcb)
{
- dprintk("RPC: rpcb_encode_mapping(%u, %u, %d, %u)\n",
+ dprintk("RPC: encoding rpcb request (%u, %u, %d, %u)\n",
rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
*p++ = htonl(rpcb->r_prog);
*p++ = htonl(rpcb->r_vers);
@@ -648,7 +639,7 @@ static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
unsigned short *portp)
{
*portp = (unsigned short) ntohl(*p++);
- dprintk("RPC: rpcb_decode_getport result %u\n",
+ dprintk("RPC: rpcb getport result: %u\n",
*portp);
return 0;
}
@@ -657,7 +648,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
unsigned int *boolp)
{
*boolp = (unsigned int) ntohl(*p++);
- dprintk("RPC: rpcb_decode_set: call %s\n",
+ dprintk("RPC: rpcb set/unset call %s\n",
(*boolp ? "succeeded" : "failed"));
return 0;
}
@@ -665,7 +656,7 @@ static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
struct rpcbind_args *rpcb)
{
- dprintk("RPC: rpcb_encode_getaddr(%u, %u, %s)\n",
+ dprintk("RPC: encoding rpcb request (%u, %u, %s)\n",
rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
*p++ = htonl(rpcb->r_prog);
*p++ = htonl(rpcb->r_vers);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 5a32cb7c4bb..54c98d87684 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,8 @@
#define RPCDBG_FACILITY RPCDBG_SVCDSP
+static void svc_unregister(const struct svc_serv *serv);
+
#define svc_serv_is_pooled(serv) ((serv)->sv_function)
/*
@@ -357,7 +359,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
*/
static struct svc_serv *
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
- void (*shutdown)(struct svc_serv *serv))
+ sa_family_t family, void (*shutdown)(struct svc_serv *serv))
{
struct svc_serv *serv;
unsigned int vers;
@@ -366,6 +368,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
+ serv->sv_family = family;
serv->sv_name = prog->pg_name;
serv->sv_program = prog;
serv->sv_nrthreads = 1;
@@ -416,30 +419,29 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
spin_lock_init(&pool->sp_lock);
}
-
/* Remove any stale portmap registrations */
- svc_register(serv, 0, 0);
+ svc_unregister(serv);
return serv;
}
struct svc_serv *
svc_create(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv))
+ sa_family_t family, void (*shutdown)(struct svc_serv *serv))
{
- return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+ return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
}
EXPORT_SYMBOL(svc_create);
struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv),
+ sa_family_t family, void (*shutdown)(struct svc_serv *serv),
svc_thread_fn func, struct module *mod)
{
struct svc_serv *serv;
unsigned int npools = svc_pool_map_get();
- serv = __svc_create(prog, bufsize, npools, shutdown);
+ serv = __svc_create(prog, bufsize, npools, family, shutdown);
if (serv != NULL) {
serv->sv_function = func;
@@ -486,8 +488,7 @@ svc_destroy(struct svc_serv *serv)
if (svc_serv_is_pooled(serv))
svc_pool_map_put();
- /* Unregister service with the portmapper */
- svc_register(serv, 0, 0);
+ svc_unregister(serv);
kfree(serv->sv_pools);
kfree(serv);
}
@@ -718,55 +719,245 @@ svc_exit_thread(struct svc_rqst *rqstp)
}
EXPORT_SYMBOL(svc_exit_thread);
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
/*
- * Register an RPC service with the local portmapper.
- * To unregister a service, call this routine with
- * proto and port == 0.
+ * Register an "inet" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
*/
-int
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
+static int __svc_rpcb_register4(const u32 program, const u32 version,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_ANY),
+ .sin_port = htons(port),
+ };
+ char *netid;
+
+ switch (protocol) {
+ case IPPROTO_UDP:
+ netid = RPCBIND_NETID_UDP;
+ break;
+ case IPPROTO_TCP:
+ netid = RPCBIND_NETID_TCP;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return rpcb_v4_register(program, version,
+ (struct sockaddr *)&sin, netid);
+}
+
+/*
+ * Register an "inet6" protocol family netid with the local
+ * rpcbind daemon via an rpcbind v4 SET request.
+ *
+ * No netconfig infrastructure is available in the kernel, so
+ * we map IP_ protocol numbers to netids by hand.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_rpcb_register6(const u32 program, const u32 version,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_port = htons(port),
+ };
+ char *netid;
+
+ switch (protocol) {
+ case IPPROTO_UDP:
+ netid = RPCBIND_NETID_UDP6;
+ break;
+ case IPPROTO_TCP:
+ netid = RPCBIND_NETID_TCP6;
+ break;
+ default:
+ return -EPROTONOSUPPORT;
+ }
+
+ return rpcb_v4_register(program, version,
+ (struct sockaddr *)&sin6, netid);
+}
+
+/*
+ * Register a kernel RPC service via rpcbind version 4.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+ const sa_family_t family,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ int error;
+
+ switch (family) {
+ case AF_INET:
+ return __svc_rpcb_register4(program, version,
+ protocol, port);
+ case AF_INET6:
+ error = __svc_rpcb_register6(program, version,
+ protocol, port);
+ if (error < 0)
+ return error;
+
+ /*
+ * Work around bug in some versions of Linux rpcbind
+ * which don't allow registration of both inet and
+ * inet6 netids.
+ *
+ * Error return ignored for now.
+ */
+ __svc_rpcb_register4(program, version,
+ protocol, port);
+ return 0;
+ }
+
+ return -EAFNOSUPPORT;
+}
+
+#else /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * Register a kernel RPC service via rpcbind version 2.
+ *
+ * Returns zero on success; a negative errno value is returned
+ * if any error occurs.
+ */
+static int __svc_register(const u32 program, const u32 version,
+ sa_family_t family,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ if (family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ return rpcb_register(program, version, protocol, port);
+}
+
+#endif /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/**
+ * svc_register - register an RPC service with the local portmapper
+ * @serv: svc_serv struct for the service to register
+ * @proto: transport protocol number to advertise
+ * @port: port to advertise
+ *
+ * Service is registered for any address in serv's address family
+ */
+int svc_register(const struct svc_serv *serv, const unsigned short proto,
+ const unsigned short port)
{
struct svc_program *progp;
- unsigned long flags;
unsigned int i;
- int error = 0, dummy;
+ int error = 0;
- if (!port)
- clear_thread_flag(TIF_SIGPENDING);
+ BUG_ON(proto == 0 && port == 0);
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
for (i = 0; i < progp->pg_nvers; i++) {
if (progp->pg_vers[i] == NULL)
continue;
- dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
+ dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
progp->pg_name,
+ i,
proto == IPPROTO_UDP? "udp" : "tcp",
port,
- i,
+ serv->sv_family,
progp->pg_vers[i]->vs_hidden?
" (but not telling portmap)" : "");
if (progp->pg_vers[i]->vs_hidden)
continue;
- error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
+ error = __svc_register(progp->pg_prog, i,
+ serv->sv_family, proto, port);
if (error < 0)
break;
- if (port && !dummy) {
- error = -EACCES;
- break;
- }
}
}
- if (!port) {
- spin_lock_irqsave(&current->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ return error;
+}
+
+#ifdef CONFIG_SUNRPC_REGISTER_V4
+
+static void __svc_unregister(const u32 program, const u32 version,
+ const char *progname)
+{
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_port = 0,
+ };
+ int error;
+
+ error = rpcb_v4_register(program, version,
+ (struct sockaddr *)&sin6, "");
+ dprintk("svc: %s(%sv%u), error %d\n",
+ __func__, progname, version, error);
+}
+
+#else /* CONFIG_SUNRPC_REGISTER_V4 */
+
+static void __svc_unregister(const u32 program, const u32 version,
+ const char *progname)
+{
+ int error;
+
+ error = rpcb_register(program, version, 0, 0);
+ dprintk("svc: %s(%sv%u), error %d\n",
+ __func__, progname, version, error);
+}
+
+#endif /* CONFIG_SUNRPC_REGISTER_V4 */
+
+/*
+ * All netids, bind addresses and ports registered for [program, version]
+ * are removed from the local rpcbind database (if the service is not
+ * hidden) to make way for a new instance of the service.
+ *
+ * The result of unregistration is reported via dprintk for those who want
+ * verification of the result, but is otherwise not important.
+ */
+static void svc_unregister(const struct svc_serv *serv)
+{
+ struct svc_program *progp;
+ unsigned long flags;
+ unsigned int i;
+
+ clear_thread_flag(TIF_SIGPENDING);
+
+ for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+ for (i = 0; i < progp->pg_nvers; i++) {
+ if (progp->pg_vers[i] == NULL)
+ continue;
+ if (progp->pg_vers[i]->vs_hidden)
+ continue;
+
+ __svc_unregister(progp->pg_prog, i, progp->pg_name);
+ }
}
- return error;
+ spin_lock_irqsave(&current->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(&current->sighand->siglock, flags);
}
/*
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index e46c825f495..bf5b5cdafeb 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -159,15 +159,44 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
}
EXPORT_SYMBOL_GPL(svc_xprt_init);
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
- int flags)
+static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
+ struct svc_serv *serv,
+ unsigned short port, int flags)
{
- struct svc_xprt_class *xcl;
struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port),
};
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_port = htons(port),
+ };
+ struct sockaddr *sap;
+ size_t len;
+
+ switch (serv->sv_family) {
+ case AF_INET:
+ sap = (struct sockaddr *)&sin;
+ len = sizeof(sin);
+ break;
+ case AF_INET6:
+ sap = (struct sockaddr *)&sin6;
+ len = sizeof(sin6);
+ break;
+ default:
+ return ERR_PTR(-EAFNOSUPPORT);
+ }
+
+ return xcl->xcl_ops->xpo_create(serv, sap, len, flags);
+}
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+ int flags)
+{
+ struct svc_xprt_class *xcl;
+
dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
spin_lock(&svc_xprt_class_lock);
list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
@@ -180,9 +209,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
goto err;
spin_unlock(&svc_xprt_class_lock);
- newxprt = xcl->xcl_ops->
- xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
- flags);
+ newxprt = __svc_xpo_create(xcl, serv, port, flags);
if (IS_ERR(newxprt)) {
module_put(xcl->xcl_owner);
return PTR_ERR(newxprt);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3e65719f1ef..95293f549e9 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1114,6 +1114,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
struct svc_sock *svsk;
struct sock *inet;
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
+ int val;
dprintk("svc: svc_setup_socket %p\n", sock);
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1146,6 +1147,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
else
svc_tcp_init(svsk, serv);
+ /*
+ * We start one listener per sv_serv. We want AF_INET
+ * requests to be automatically shunted to our AF_INET6
+ * listener using a mapped IPv4 address. Make sure
+ * no-one starts an equivalent IPv4 listener, which
+ * would steal our incoming connections.
+ */
+ val = 0;
+ if (serv->sv_family == AF_INET6)
+ kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+ (char *)&val, sizeof(val));
+
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
svsk, svsk->sk_sk);
@@ -1154,8 +1167,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
int svc_addsock(struct svc_serv *serv,
int fd,
- char *name_return,
- int *proto)
+ char *name_return)
{
int err = 0;
struct socket *so = sockfd_lookup(fd, &err);
@@ -1190,7 +1202,6 @@ int svc_addsock(struct svc_serv *serv,
sockfd_put(so);
return err;
}
- if (proto) *proto = so->sk->sk_protocol;
return one_sock_name(name_return, svsk);
}
EXPORT_SYMBOL_GPL(svc_addsock);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
index 74de31a0661..a4756576d68 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
@@ -116,7 +116,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
*
* Assumptions:
* - chunk[0]->position points to pages[0] at an offset of 0
- * - pages[] is not physically or virtually contigous and consists of
+ * - pages[] is not physically or virtually contiguous and consists of
* PAGE_SIZE elements.
*
* Output:
@@ -125,7 +125,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
* chunk in the read list
*
*/
-static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
+static int map_read_chunks(struct svcxprt_rdma *xprt,
struct svc_rqst *rqstp,
struct svc_rdma_op_ctxt *head,
struct rpcrdma_msg *rmsgp,
@@ -211,26 +211,128 @@ static int rdma_rcl_to_sge(struct svcxprt_rdma *xprt,
return sge_no;
}
-static void rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
- struct svc_rdma_op_ctxt *ctxt,
- struct kvec *vec,
- u64 *sgl_offset,
- int count)
+/* Map a read-chunk-list to an XDR and fast register the page-list.
+ *
+ * Assumptions:
+ * - chunk[0] position points to pages[0] at an offset of 0
+ * - pages[] will be made physically contiguous by creating a one-off memory
+ * region using the fastreg verb.
+ * - byte_count is # of bytes in read-chunk-list
+ * - ch_count is # of chunks in read-chunk-list
+ *
+ * Output:
+ * - sge array pointing into pages[] array.
+ * - chunk_sge array specifying sge index and count for each
+ * chunk in the read list
+ */
+static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
+ struct svc_rqst *rqstp,
+ struct svc_rdma_op_ctxt *head,
+ struct rpcrdma_msg *rmsgp,
+ struct svc_rdma_req_map *rpl_map,
+ struct svc_rdma_req_map *chl_map,
+ int ch_count,
+ int byte_count)
+{
+ int page_no;
+ int ch_no;
+ u32 offset;
+ struct rpcrdma_read_chunk *ch;
+ struct svc_rdma_fastreg_mr *frmr;
+ int ret = 0;
+
+ frmr = svc_rdma_get_frmr(xprt);
+ if (IS_ERR(frmr))
+ return -ENOMEM;
+
+ head->frmr = frmr;
+ head->arg.head[0] = rqstp->rq_arg.head[0];
+ head->arg.tail[0] = rqstp->rq_arg.tail[0];
+ head->arg.pages = &head->pages[head->count];
+ head->hdr_count = head->count; /* save count of hdr pages */
+ head->arg.page_base = 0;
+ head->arg.page_len = byte_count;
+ head->arg.len = rqstp->rq_arg.len + byte_count;
+ head->arg.buflen = rqstp->rq_arg.buflen + byte_count;
+
+ /* Fast register the page list */
+ frmr->kva = page_address(rqstp->rq_arg.pages[0]);
+ frmr->direction = DMA_FROM_DEVICE;
+ frmr->access_flags = (IB_ACCESS_LOCAL_WRITE|IB_ACCESS_REMOTE_WRITE);
+ frmr->map_len = byte_count;
+ frmr->page_list_len = PAGE_ALIGN(byte_count) >> PAGE_SHIFT;
+ for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+ frmr->page_list->page_list[page_no] =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ page_address(rqstp->rq_arg.pages[page_no]),
+ PAGE_SIZE, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ frmr->page_list->page_list[page_no]))
+ goto fatal_err;
+ atomic_inc(&xprt->sc_dma_used);
+ head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
+ }
+ head->count += page_no;
+
+ /* rq_respages points one past arg pages */
+ rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+
+ /* Create the reply and chunk maps */
+ offset = 0;
+ ch = (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0];
+ for (ch_no = 0; ch_no < ch_count; ch_no++) {
+ rpl_map->sge[ch_no].iov_base = frmr->kva + offset;
+ rpl_map->sge[ch_no].iov_len = ch->rc_target.rs_length;
+ chl_map->ch[ch_no].count = 1;
+ chl_map->ch[ch_no].start = ch_no;
+ offset += ch->rc_target.rs_length;
+ ch++;
+ }
+
+ ret = svc_rdma_fastreg(xprt, frmr);
+ if (ret)
+ goto fatal_err;
+
+ return ch_no;
+
+ fatal_err:
+ printk("svcrdma: error fast registering xdr for xprt %p", xprt);
+ svc_rdma_put_frmr(xprt, frmr);
+ return -EIO;
+}
+
+static int rdma_set_ctxt_sge(struct svcxprt_rdma *xprt,
+ struct svc_rdma_op_ctxt *ctxt,
+ struct svc_rdma_fastreg_mr *frmr,
+ struct kvec *vec,
+ u64 *sgl_offset,
+ int count)
{
int i;
ctxt->count = count;
ctxt->direction = DMA_FROM_DEVICE;
for (i = 0; i < count; i++) {
- atomic_inc(&xprt->sc_dma_used);
- ctxt->sge[i].addr =
- ib_dma_map_single(xprt->sc_cm_id->device,
- vec[i].iov_base, vec[i].iov_len,
- DMA_FROM_DEVICE);
+ ctxt->sge[i].length = 0; /* in case map fails */
+ if (!frmr) {
+ ctxt->sge[i].addr =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ vec[i].iov_base,
+ vec[i].iov_len,
+ DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ ctxt->sge[i].addr))
+ return -EINVAL;
+ ctxt->sge[i].lkey = xprt->sc_dma_lkey;
+ atomic_inc(&xprt->sc_dma_used);
+ } else {
+ ctxt->sge[i].addr = (unsigned long)vec[i].iov_base;
+ ctxt->sge[i].lkey = frmr->mr->lkey;
+ }
ctxt->sge[i].length = vec[i].iov_len;
- ctxt->sge[i].lkey = xprt->sc_phys_mr->lkey;
*sgl_offset = *sgl_offset + vec[i].iov_len;
}
+ return 0;
}
static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count)
@@ -278,6 +380,7 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
struct svc_rdma_op_ctxt *hdr_ctxt)
{
struct ib_send_wr read_wr;
+ struct ib_send_wr inv_wr;
int err = 0;
int ch_no;
int ch_count;
@@ -301,9 +404,20 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
svc_rdma_rcl_chunk_counts(ch, &ch_count, &byte_count);
if (ch_count > RPCSVC_MAXPAGES)
return -EINVAL;
- sge_count = rdma_rcl_to_sge(xprt, rqstp, hdr_ctxt, rmsgp,
- rpl_map, chl_map,
- ch_count, byte_count);
+
+ if (!xprt->sc_frmr_pg_list_len)
+ sge_count = map_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+ rpl_map, chl_map, ch_count,
+ byte_count);
+ else
+ sge_count = fast_reg_read_chunks(xprt, rqstp, hdr_ctxt, rmsgp,
+ rpl_map, chl_map, ch_count,
+ byte_count);
+ if (sge_count < 0) {
+ err = -EIO;
+ goto out;
+ }
+
sgl_offset = 0;
ch_no = 0;
@@ -312,13 +426,16 @@ static int rdma_read_xdr(struct svcxprt_rdma *xprt,
next_sge:
ctxt = svc_rdma_get_context(xprt);
ctxt->direction = DMA_FROM_DEVICE;
+ ctxt->frmr = hdr_ctxt->frmr;
+ ctxt->read_hdr = NULL;
clear_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+ clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
/* Prepare READ WR */
memset(&read_wr, 0, sizeof read_wr);
- ctxt->wr_op = IB_WR_RDMA_READ;
read_wr.wr_id = (unsigned long)ctxt;
read_wr.opcode = IB_WR_RDMA_READ;
+ ctxt->wr_op = read_wr.opcode;
read_wr.send_flags = IB_SEND_SIGNALED;
read_wr.wr.rdma.rkey = ch->rc_target.rs_handle;
read_wr.wr.rdma.remote_addr =
@@ -327,10 +444,15 @@ next_sge:
read_wr.sg_list = ctxt->sge;
read_wr.num_sge =
rdma_read_max_sge(xprt, chl_map->ch[ch_no].count);
- rdma_set_ctxt_sge(xprt, ctxt,
- &rpl_map->sge[chl_map->ch[ch_no].start],
- &sgl_offset,
- read_wr.num_sge);
+ err = rdma_set_ctxt_sge(xprt, ctxt, hdr_ctxt->frmr,
+ &rpl_map->sge[chl_map->ch[ch_no].start],
+ &sgl_offset,
+ read_wr.num_sge);
+ if (err) {
+ svc_rdma_unmap_dma(ctxt);
+ svc_rdma_put_context(ctxt, 0);
+ goto out;
+ }
if (((ch+1)->rc_discrim == 0) &&
(read_wr.num_sge == chl_map->ch[ch_no].count)) {
/*
@@ -339,6 +461,29 @@ next_sge:
* the client and the RPC needs to be enqueued.
*/
set_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags);
+ if (hdr_ctxt->frmr) {
+ set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+ /*
+ * Invalidate the local MR used to map the data
+ * sink.
+ */
+ if (xprt->sc_dev_caps &
+ SVCRDMA_DEVCAP_READ_W_INV) {
+ read_wr.opcode =
+ IB_WR_RDMA_READ_WITH_INV;
+ ctxt->wr_op = read_wr.opcode;
+ read_wr.ex.invalidate_rkey =
+ ctxt->frmr->mr->lkey;
+ } else {
+ /* Prepare INVALIDATE WR */
+ memset(&inv_wr, 0, sizeof inv_wr);
+ inv_wr.opcode = IB_WR_LOCAL_INV;
+ inv_wr.send_flags = IB_SEND_SIGNALED;
+ inv_wr.ex.invalidate_rkey =
+ hdr_ctxt->frmr->mr->lkey;
+ read_wr.next = &inv_wr;
+ }
+ }
ctxt->read_hdr = hdr_ctxt;
}
/* Post the read */
diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
index 84d328329d9..9a7a8e7ae03 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c
@@ -69,9 +69,127 @@
* array is only concerned with the reply we are assured that we have
* on extra page for the RPCRMDA header.
*/
-static void xdr_to_sge(struct svcxprt_rdma *xprt,
- struct xdr_buf *xdr,
- struct svc_rdma_req_map *vec)
+int fast_reg_xdr(struct svcxprt_rdma *xprt,
+ struct xdr_buf *xdr,
+ struct svc_rdma_req_map *vec)
+{
+ int sge_no;
+ u32 sge_bytes;
+ u32 page_bytes;
+ u32 page_off;
+ int page_no = 0;
+ u8 *frva;
+ struct svc_rdma_fastreg_mr *frmr;
+
+ frmr = svc_rdma_get_frmr(xprt);
+ if (IS_ERR(frmr))
+ return -ENOMEM;
+ vec->frmr = frmr;
+
+ /* Skip the RPCRDMA header */
+ sge_no = 1;
+
+ /* Map the head. */
+ frva = (void *)((unsigned long)(xdr->head[0].iov_base) & PAGE_MASK);
+ vec->sge[sge_no].iov_base = xdr->head[0].iov_base;
+ vec->sge[sge_no].iov_len = xdr->head[0].iov_len;
+ vec->count = 2;
+ sge_no++;
+
+ /* Build the FRMR */
+ frmr->kva = frva;
+ frmr->direction = DMA_TO_DEVICE;
+ frmr->access_flags = 0;
+ frmr->map_len = PAGE_SIZE;
+ frmr->page_list_len = 1;
+ frmr->page_list->page_list[page_no] =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ (void *)xdr->head[0].iov_base,
+ PAGE_SIZE, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ frmr->page_list->page_list[page_no]))
+ goto fatal_err;
+ atomic_inc(&xprt->sc_dma_used);
+
+ page_off = xdr->page_base;
+ page_bytes = xdr->page_len + page_off;
+ if (!page_bytes)
+ goto encode_tail;
+
+ /* Map the pages */
+ vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+ vec->sge[sge_no].iov_len = page_bytes;
+ sge_no++;
+ while (page_bytes) {
+ struct page *page;
+
+ page = xdr->pages[page_no++];
+ sge_bytes = min_t(u32, page_bytes, (PAGE_SIZE - page_off));
+ page_bytes -= sge_bytes;
+
+ frmr->page_list->page_list[page_no] =
+ ib_dma_map_page(xprt->sc_cm_id->device, page, 0,
+ PAGE_SIZE, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ frmr->page_list->page_list[page_no]))
+ goto fatal_err;
+
+ atomic_inc(&xprt->sc_dma_used);
+ page_off = 0; /* reset for next time through loop */
+ frmr->map_len += PAGE_SIZE;
+ frmr->page_list_len++;
+ }
+ vec->count++;
+
+ encode_tail:
+ /* Map tail */
+ if (0 == xdr->tail[0].iov_len)
+ goto done;
+
+ vec->count++;
+ vec->sge[sge_no].iov_len = xdr->tail[0].iov_len;
+
+ if (((unsigned long)xdr->tail[0].iov_base & PAGE_MASK) ==
+ ((unsigned long)xdr->head[0].iov_base & PAGE_MASK)) {
+ /*
+ * If head and tail use the same page, we don't need
+ * to map it again.
+ */
+ vec->sge[sge_no].iov_base = xdr->tail[0].iov_base;
+ } else {
+ void *va;
+
+ /* Map another page for the tail */
+ page_off = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK;
+ va = (void *)((unsigned long)xdr->tail[0].iov_base & PAGE_MASK);
+ vec->sge[sge_no].iov_base = frva + frmr->map_len + page_off;
+
+ frmr->page_list->page_list[page_no] =
+ ib_dma_map_single(xprt->sc_cm_id->device, va, PAGE_SIZE,
+ DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ frmr->page_list->page_list[page_no]))
+ goto fatal_err;
+ atomic_inc(&xprt->sc_dma_used);
+ frmr->map_len += PAGE_SIZE;
+ frmr->page_list_len++;
+ }
+
+ done:
+ if (svc_rdma_fastreg(xprt, frmr))
+ goto fatal_err;
+
+ return 0;
+
+ fatal_err:
+ printk("svcrdma: Error fast registering memory for xprt %p\n", xprt);
+ svc_rdma_put_frmr(xprt, frmr);
+ return -EIO;
+}
+
+static int map_xdr(struct svcxprt_rdma *xprt,
+ struct xdr_buf *xdr,
+ struct svc_rdma_req_map *vec)
{
int sge_max = (xdr->len+PAGE_SIZE-1) / PAGE_SIZE + 3;
int sge_no;
@@ -83,6 +201,9 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
BUG_ON(xdr->len !=
(xdr->head[0].iov_len + xdr->page_len + xdr->tail[0].iov_len));
+ if (xprt->sc_frmr_pg_list_len)
+ return fast_reg_xdr(xprt, xdr, vec);
+
/* Skip the first sge, this is for the RPCRDMA header */
sge_no = 1;
@@ -116,9 +237,12 @@ static void xdr_to_sge(struct svcxprt_rdma *xprt,
BUG_ON(sge_no > sge_max);
vec->count = sge_no;
+ return 0;
}
/* Assumptions:
+ * - We are using FRMR
+ * - or -
* - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
*/
static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
@@ -158,30 +282,35 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
sge_no = 0;
/* Copy the remaining SGE */
- while (bc != 0 && xdr_sge_no < vec->count) {
- sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
- sge_bytes = min((size_t)bc,
- (size_t)(vec->sge[xdr_sge_no].iov_len-sge_off));
+ while (bc != 0) {
+ sge_bytes = min_t(size_t,
+ bc, vec->sge[xdr_sge_no].iov_len-sge_off);
sge[sge_no].length = sge_bytes;
- atomic_inc(&xprt->sc_dma_used);
- sge[sge_no].addr =
- ib_dma_map_single(xprt->sc_cm_id->device,
- (void *)
- vec->sge[xdr_sge_no].iov_base + sge_off,
- sge_bytes, DMA_TO_DEVICE);
- if (dma_mapping_error(xprt->sc_cm_id->device->dma_device,
- sge[sge_no].addr))
- goto err;
+ if (!vec->frmr) {
+ sge[sge_no].addr =
+ ib_dma_map_single(xprt->sc_cm_id->device,
+ (void *)
+ vec->sge[xdr_sge_no].iov_base + sge_off,
+ sge_bytes, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device,
+ sge[sge_no].addr))
+ goto err;
+ atomic_inc(&xprt->sc_dma_used);
+ sge[sge_no].lkey = xprt->sc_dma_lkey;
+ } else {
+ sge[sge_no].addr = (unsigned long)
+ vec->sge[xdr_sge_no].iov_base + sge_off;
+ sge[sge_no].lkey = vec->frmr->mr->lkey;
+ }
+ ctxt->count++;
+ ctxt->frmr = vec->frmr;
sge_off = 0;
sge_no++;
- ctxt->count++;
xdr_sge_no++;
+ BUG_ON(xdr_sge_no > vec->count);
bc -= sge_bytes;
}
- BUG_ON(bc != 0);
- BUG_ON(xdr_sge_no > vec->count);
-
/* Prepare WRITE WR */
memset(&write_wr, 0, sizeof write_wr);
ctxt->wr_op = IB_WR_RDMA_WRITE;
@@ -226,7 +355,10 @@ static int send_write_chunks(struct svcxprt_rdma *xprt,
res_ary = (struct rpcrdma_write_array *)
&rdma_resp->rm_body.rm_chunks[1];
- max_write = xprt->sc_max_sge * PAGE_SIZE;
+ if (vec->frmr)
+ max_write = vec->frmr->map_len;
+ else
+ max_write = xprt->sc_max_sge * PAGE_SIZE;
/* Write chunks start at the pagelist */
for (xdr_off = rqstp->rq_res.head[0].iov_len, chunk_no = 0;
@@ -297,7 +429,10 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
res_ary = (struct rpcrdma_write_array *)
&rdma_resp->rm_body.rm_chunks[2];
- max_write = xprt->sc_max_sge * PAGE_SIZE;
+ if (vec->frmr)
+ max_write = vec->frmr->map_len;
+ else
+ max_write = xprt->sc_max_sge * PAGE_SIZE;
/* xdr offset starts at RPC message */
for (xdr_off = 0, chunk_no = 0;
@@ -307,7 +442,6 @@ static int send_reply_chunks(struct svcxprt_rdma *xprt,
ch = &arg_ary->wc_array[chunk_no].wc_target;
write_len = min(xfer_len, ch->rs_length);
-
/* Prepare the reply chunk given the length actually
* written */
rs_offset = get_unaligned(&(ch->rs_offset));
@@ -366,6 +500,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
int byte_count)
{
struct ib_send_wr send_wr;
+ struct ib_send_wr inv_wr;
int sge_no;
int sge_bytes;
int page_no;
@@ -385,27 +520,45 @@ static int send_reply(struct svcxprt_rdma *rdma,
/* Prepare the context */
ctxt->pages[0] = page;
ctxt->count = 1;
+ ctxt->frmr = vec->frmr;
+ if (vec->frmr)
+ set_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
+ else
+ clear_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags);
/* Prepare the SGE for the RPCRDMA Header */
- atomic_inc(&rdma->sc_dma_used);
ctxt->sge[0].addr =
ib_dma_map_page(rdma->sc_cm_id->device,
page, 0, PAGE_SIZE, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
+ goto err;
+ atomic_inc(&rdma->sc_dma_used);
+
ctxt->direction = DMA_TO_DEVICE;
+
ctxt->sge[0].length = svc_rdma_xdr_get_reply_hdr_len(rdma_resp);
- ctxt->sge[0].lkey = rdma->sc_phys_mr->lkey;
+ ctxt->sge[0].lkey = rdma->sc_dma_lkey;
/* Determine how many of our SGE are to be transmitted */
for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) {
sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count);
byte_count -= sge_bytes;
- atomic_inc(&rdma->sc_dma_used);
- ctxt->sge[sge_no].addr =
- ib_dma_map_single(rdma->sc_cm_id->device,
- vec->sge[sge_no].iov_base,
- sge_bytes, DMA_TO_DEVICE);
+ if (!vec->frmr) {
+ ctxt->sge[sge_no].addr =
+ ib_dma_map_single(rdma->sc_cm_id->device,
+ vec->sge[sge_no].iov_base,
+ sge_bytes, DMA_TO_DEVICE);
+ if (ib_dma_mapping_error(rdma->sc_cm_id->device,
+ ctxt->sge[sge_no].addr))
+ goto err;
+ atomic_inc(&rdma->sc_dma_used);
+ ctxt->sge[sge_no].lkey = rdma->sc_dma_lkey;
+ } else {
+ ctxt->sge[sge_no].addr = (unsigned long)
+ vec->sge[sge_no].iov_base;
+ ctxt->sge[sge_no].lkey = vec->frmr->mr->lkey;
+ }
ctxt->sge[sge_no].length = sge_bytes;
- ctxt->sge[sge_no].lkey = rdma->sc_phys_mr->lkey;
}
BUG_ON(byte_count != 0);
@@ -417,11 +570,16 @@ static int send_reply(struct svcxprt_rdma *rdma,
ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
ctxt->count++;
rqstp->rq_respages[page_no] = NULL;
- /* If there are more pages than SGE, terminate SGE list */
+ /*
+ * If there are more pages than SGE, terminate SGE
+ * list so that svc_rdma_unmap_dma doesn't attempt to
+ * unmap garbage.
+ */
if (page_no+1 >= sge_no)
ctxt->sge[page_no+1].length = 0;
}
BUG_ON(sge_no > rdma->sc_max_sge);
+ BUG_ON(sge_no > ctxt->count);
memset(&send_wr, 0, sizeof send_wr);
ctxt->wr_op = IB_WR_SEND;
send_wr.wr_id = (unsigned long)ctxt;
@@ -429,12 +587,26 @@ static int send_reply(struct svcxprt_rdma *rdma,
send_wr.num_sge = sge_no;
send_wr.opcode = IB_WR_SEND;
send_wr.send_flags = IB_SEND_SIGNALED;
+ if (vec->frmr) {
+ /* Prepare INVALIDATE WR */
+ memset(&inv_wr, 0, sizeof inv_wr);
+ inv_wr.opcode = IB_WR_LOCAL_INV;
+ inv_wr.send_flags = IB_SEND_SIGNALED;
+ inv_wr.ex.invalidate_rkey =
+ vec->frmr->mr->lkey;
+ send_wr.next = &inv_wr;
+ }
ret = svc_rdma_send(rdma, &send_wr);
if (ret)
- svc_rdma_put_context(ctxt, 1);
+ goto err;
- return ret;
+ return 0;
+
+ err:
+ svc_rdma_put_frmr(rdma, vec->frmr);
+ svc_rdma_put_context(ctxt, 1);
+ return -EIO;
}
void svc_rdma_prep_reply_hdr(struct svc_rqst *rqstp)
@@ -477,8 +649,9 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
ctxt = svc_rdma_get_context(rdma);
ctxt->direction = DMA_TO_DEVICE;
vec = svc_rdma_get_req_map();
- xdr_to_sge(rdma, &rqstp->rq_res, vec);
-
+ ret = map_xdr(rdma, &rqstp->rq_res, vec);
+ if (ret)
+ goto err0;
inline_bytes = rqstp->rq_res.len;
/* Create the RDMA response header */
@@ -498,7 +671,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
if (ret < 0) {
printk(KERN_ERR "svcrdma: failed to send write chunks, rc=%d\n",
ret);
- goto error;
+ goto err1;
}
inline_bytes -= ret;
@@ -508,7 +681,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
if (ret < 0) {
printk(KERN_ERR "svcrdma: failed to send reply chunks, rc=%d\n",
ret);
- goto error;
+ goto err1;
}
inline_bytes -= ret;
@@ -517,9 +690,11 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
svc_rdma_put_req_map(vec);
dprintk("svcrdma: send_reply returns %d\n", ret);
return ret;
- error:
+
+ err1:
+ put_page(res_page);
+ err0:
svc_rdma_put_req_map(vec);
svc_rdma_put_context(ctxt, 0);
- put_page(res_page);
return ret;
}
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 900cb69728c..6fb493cbd29 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -100,20 +100,29 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
ctxt->xprt = xprt;
INIT_LIST_HEAD(&ctxt->dto_q);
ctxt->count = 0;
+ ctxt->frmr = NULL;
atomic_inc(&xprt->sc_ctxt_used);
return ctxt;
}
-static void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
+void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
{
struct svcxprt_rdma *xprt = ctxt->xprt;
int i;
for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
- atomic_dec(&xprt->sc_dma_used);
- ib_dma_unmap_single(xprt->sc_cm_id->device,
- ctxt->sge[i].addr,
- ctxt->sge[i].length,
- ctxt->direction);
+ /*
+ * Unmap the DMA addr in the SGE if the lkey matches
+ * the sc_dma_lkey, otherwise, ignore it since it is
+ * an FRMR lkey and will be unmapped later when the
+ * last WR that uses it completes.
+ */
+ if (ctxt->sge[i].lkey == xprt->sc_dma_lkey) {
+ atomic_dec(&xprt->sc_dma_used);
+ ib_dma_unmap_single(xprt->sc_cm_id->device,
+ ctxt->sge[i].addr,
+ ctxt->sge[i].length,
+ ctxt->direction);
+ }
}
}
@@ -150,6 +159,7 @@ struct svc_rdma_req_map *svc_rdma_get_req_map(void)
schedule_timeout_uninterruptible(msecs_to_jiffies(500));
}
map->count = 0;
+ map->frmr = NULL;
return map;
}
@@ -316,6 +326,50 @@ static void rq_cq_reap(struct svcxprt_rdma *xprt)
}
/*
+ * Processs a completion context
+ */
+static void process_context(struct svcxprt_rdma *xprt,
+ struct svc_rdma_op_ctxt *ctxt)
+{
+ svc_rdma_unmap_dma(ctxt);
+
+ switch (ctxt->wr_op) {
+ case IB_WR_SEND:
+ if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+ svc_rdma_put_frmr(xprt, ctxt->frmr);
+ svc_rdma_put_context(ctxt, 1);
+ break;
+
+ case IB_WR_RDMA_WRITE:
+ svc_rdma_put_context(ctxt, 0);
+ break;
+
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_READ_WITH_INV:
+ if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
+ struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
+ BUG_ON(!read_hdr);
+ if (test_bit(RDMACTXT_F_FAST_UNREG, &ctxt->flags))
+ svc_rdma_put_frmr(xprt, ctxt->frmr);
+ spin_lock_bh(&xprt->sc_rq_dto_lock);
+ set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
+ list_add_tail(&read_hdr->dto_q,
+ &xprt->sc_read_complete_q);
+ spin_unlock_bh(&xprt->sc_rq_dto_lock);
+ svc_xprt_enqueue(&xprt->sc_xprt);
+ }
+ svc_rdma_put_context(ctxt, 0);
+ break;
+
+ default:
+ printk(KERN_ERR "svcrdma: unexpected completion type, "
+ "opcode=%d\n",
+ ctxt->wr_op);
+ break;
+ }
+}
+
+/*
* Send Queue Completion Handler - potentially called on interrupt context.
*
* Note that caller must hold a transport reference.
@@ -327,17 +381,12 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
struct ib_cq *cq = xprt->sc_sq_cq;
int ret;
-
if (!test_and_clear_bit(RDMAXPRT_SQ_PENDING, &xprt->sc_flags))
return;
ib_req_notify_cq(xprt->sc_sq_cq, IB_CQ_NEXT_COMP);
atomic_inc(&rdma_stat_sq_poll);
while ((ret = ib_poll_cq(cq, 1, &wc)) > 0) {
- ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
- xprt = ctxt->xprt;
-
- svc_rdma_unmap_dma(ctxt);
if (wc.status != IB_WC_SUCCESS)
/* Close the transport */
set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
@@ -346,35 +395,10 @@ static void sq_cq_reap(struct svcxprt_rdma *xprt)
atomic_dec(&xprt->sc_sq_count);
wake_up(&xprt->sc_send_wait);
- switch (ctxt->wr_op) {
- case IB_WR_SEND:
- svc_rdma_put_context(ctxt, 1);
- break;
-
- case IB_WR_RDMA_WRITE:
- svc_rdma_put_context(ctxt, 0);
- break;
-
- case IB_WR_RDMA_READ:
- if (test_bit(RDMACTXT_F_LAST_CTXT, &ctxt->flags)) {
- struct svc_rdma_op_ctxt *read_hdr = ctxt->read_hdr;
- BUG_ON(!read_hdr);
- spin_lock_bh(&xprt->sc_rq_dto_lock);
- set_bit(XPT_DATA, &xprt->sc_xprt.xpt_flags);
- list_add_tail(&read_hdr->dto_q,
- &xprt->sc_read_complete_q);
- spin_unlock_bh(&xprt->sc_rq_dto_lock);
- svc_xprt_enqueue(&xprt->sc_xprt);
- }
- svc_rdma_put_context(ctxt, 0);
- break;
+ ctxt = (struct svc_rdma_op_ctxt *)(unsigned long)wc.wr_id;
+ if (ctxt)
+ process_context(xprt, ctxt);
- default:
- printk(KERN_ERR "svcrdma: unexpected completion type, "
- "opcode=%d, status=%d\n",
- wc.opcode, wc.status);
- break;
- }
svc_xprt_put(&xprt->sc_xprt);
}
@@ -425,10 +449,12 @@ static struct svcxprt_rdma *rdma_create_xprt(struct svc_serv *serv,
INIT_LIST_HEAD(&cma_xprt->sc_dto_q);
INIT_LIST_HEAD(&cma_xprt->sc_rq_dto_q);
INIT_LIST_HEAD(&cma_xprt->sc_read_complete_q);
+ INIT_LIST_HEAD(&cma_xprt->sc_frmr_q);
init_waitqueue_head(&cma_xprt->sc_send_wait);
spin_lock_init(&cma_xprt->sc_lock);
spin_lock_init(&cma_xprt->sc_rq_dto_lock);
+ spin_lock_init(&cma_xprt->sc_frmr_q_lock);
cma_xprt->sc_ord = svcrdma_ord;
@@ -462,7 +488,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
struct ib_recv_wr recv_wr, *bad_recv_wr;
struct svc_rdma_op_ctxt *ctxt;
struct page *page;
- unsigned long pa;
+ dma_addr_t pa;
int sge_no;
int buflen;
int ret;
@@ -474,13 +500,15 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
BUG_ON(sge_no >= xprt->sc_max_sge);
page = svc_rdma_get_page();
ctxt->pages[sge_no] = page;
- atomic_inc(&xprt->sc_dma_used);
pa = ib_dma_map_page(xprt->sc_cm_id->device,
page, 0, PAGE_SIZE,
DMA_FROM_DEVICE);
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
+ goto err_put_ctxt;
+ atomic_inc(&xprt->sc_dma_used);
ctxt->sge[sge_no].addr = pa;
ctxt->sge[sge_no].length = PAGE_SIZE;
- ctxt->sge[sge_no].lkey = xprt->sc_phys_mr->lkey;
+ ctxt->sge[sge_no].lkey = xprt->sc_dma_lkey;
buflen += PAGE_SIZE;
}
ctxt->count = sge_no;
@@ -496,6 +524,10 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt)
svc_rdma_put_context(ctxt, 1);
}
return ret;
+
+ err_put_ctxt:
+ svc_rdma_put_context(ctxt, 1);
+ return -ENOMEM;
}
/*
@@ -566,7 +598,7 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
"event=%d\n", cma_id, cma_id->context, event->event);
handle_connect_req(cma_id,
- event->param.conn.responder_resources);
+ event->param.conn.initiator_depth);
break;
case RDMA_CM_EVENT_ESTABLISHED:
@@ -686,6 +718,97 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
return ERR_PTR(ret);
}
+static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt)
+{
+ struct ib_mr *mr;
+ struct ib_fast_reg_page_list *pl;
+ struct svc_rdma_fastreg_mr *frmr;
+
+ frmr = kmalloc(sizeof(*frmr), GFP_KERNEL);
+ if (!frmr)
+ goto err;
+
+ mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES);
+ if (!mr)
+ goto err_free_frmr;
+
+ pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device,
+ RPCSVC_MAXPAGES);
+ if (!pl)
+ goto err_free_mr;
+
+ frmr->mr = mr;
+ frmr->page_list = pl;
+ INIT_LIST_HEAD(&frmr->frmr_list);
+ return frmr;
+
+ err_free_mr:
+ ib_dereg_mr(mr);
+ err_free_frmr:
+ kfree(frmr);
+ err:
+ return ERR_PTR(-ENOMEM);
+}
+
+static void rdma_dealloc_frmr_q(struct svcxprt_rdma *xprt)
+{
+ struct svc_rdma_fastreg_mr *frmr;
+
+ while (!list_empty(&xprt->sc_frmr_q)) {
+ frmr = list_entry(xprt->sc_frmr_q.next,
+ struct svc_rdma_fastreg_mr, frmr_list);
+ list_del_init(&frmr->frmr_list);
+ ib_dereg_mr(frmr->mr);
+ ib_free_fast_reg_page_list(frmr->page_list);
+ kfree(frmr);
+ }
+}
+
+struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *rdma)
+{
+ struct svc_rdma_fastreg_mr *frmr = NULL;
+
+ spin_lock_bh(&rdma->sc_frmr_q_lock);
+ if (!list_empty(&rdma->sc_frmr_q)) {
+ frmr = list_entry(rdma->sc_frmr_q.next,
+ struct svc_rdma_fastreg_mr, frmr_list);
+ list_del_init(&frmr->frmr_list);
+ frmr->map_len = 0;
+ frmr->page_list_len = 0;
+ }
+ spin_unlock_bh(&rdma->sc_frmr_q_lock);
+ if (frmr)
+ return frmr;
+
+ return rdma_alloc_frmr(rdma);
+}
+
+static void frmr_unmap_dma(struct svcxprt_rdma *xprt,
+ struct svc_rdma_fastreg_mr *frmr)
+{
+ int page_no;
+ for (page_no = 0; page_no < frmr->page_list_len; page_no++) {
+ dma_addr_t addr = frmr->page_list->page_list[page_no];
+ if (ib_dma_mapping_error(frmr->mr->device, addr))
+ continue;
+ atomic_dec(&xprt->sc_dma_used);
+ ib_dma_unmap_single(frmr->mr->device, addr, PAGE_SIZE,
+ frmr->direction);
+ }
+}
+
+void svc_rdma_put_frmr(struct svcxprt_rdma *rdma,
+ struct svc_rdma_fastreg_mr *frmr)
+{
+ if (frmr) {
+ frmr_unmap_dma(rdma, frmr);
+ spin_lock_bh(&rdma->sc_frmr_q_lock);
+ BUG_ON(!list_empty(&frmr->frmr_list));
+ list_add(&frmr->frmr_list, &rdma->sc_frmr_q);
+ spin_unlock_bh(&rdma->sc_frmr_q_lock);
+ }
+}
+
/*
* This is the xpo_recvfrom function for listening endpoints. Its
* purpose is to accept incoming connections. The CMA callback handler
@@ -704,6 +827,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
struct rdma_conn_param conn_param;
struct ib_qp_init_attr qp_attr;
struct ib_device_attr devattr;
+ int dma_mr_acc;
+ int need_dma_mr;
int ret;
int i;
@@ -819,15 +944,77 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
}
newxprt->sc_qp = newxprt->sc_cm_id->qp;
- /* Register all of physical memory */
- newxprt->sc_phys_mr = ib_get_dma_mr(newxprt->sc_pd,
- IB_ACCESS_LOCAL_WRITE |
- IB_ACCESS_REMOTE_WRITE);
- if (IS_ERR(newxprt->sc_phys_mr)) {
- dprintk("svcrdma: Failed to create DMA MR ret=%d\n", ret);
+ /*
+ * Use the most secure set of MR resources based on the
+ * transport type and available memory management features in
+ * the device. Here's the table implemented below:
+ *
+ * Fast Global DMA Remote WR
+ * Reg LKEY MR Access
+ * Sup'd Sup'd Needed Needed
+ *
+ * IWARP N N Y Y
+ * N Y Y Y
+ * Y N Y N
+ * Y Y N -
+ *
+ * IB N N Y N
+ * N Y N -
+ * Y N Y N
+ * Y Y N -
+ *
+ * NB: iWARP requires remote write access for the data sink
+ * of an RDMA_READ. IB does not.
+ */
+ if (devattr.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
+ newxprt->sc_frmr_pg_list_len =
+ devattr.max_fast_reg_page_list_len;
+ newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
+ }
+
+ /*
+ * Determine if a DMA MR is required and if so, what privs are required
+ */
+ switch (rdma_node_get_transport(newxprt->sc_cm_id->device->node_type)) {
+ case RDMA_TRANSPORT_IWARP:
+ newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_READ_W_INV;
+ if (!(newxprt->sc_dev_caps & SVCRDMA_DEVCAP_FAST_REG)) {
+ need_dma_mr = 1;
+ dma_mr_acc =
+ (IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE);
+ } else if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+ need_dma_mr = 1;
+ dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+ } else
+ need_dma_mr = 0;
+ break;
+ case RDMA_TRANSPORT_IB:
+ if (!(devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY)) {
+ need_dma_mr = 1;
+ dma_mr_acc = IB_ACCESS_LOCAL_WRITE;
+ } else
+ need_dma_mr = 0;
+ break;
+ default:
goto errout;
}
+ /* Create the DMA MR if needed, otherwise, use the DMA LKEY */
+ if (need_dma_mr) {
+ /* Register all of physical memory */
+ newxprt->sc_phys_mr =
+ ib_get_dma_mr(newxprt->sc_pd, dma_mr_acc);
+ if (IS_ERR(newxprt->sc_phys_mr)) {
+ dprintk("svcrdma: Failed to create DMA MR ret=%d\n",
+ ret);
+ goto errout;
+ }
+ newxprt->sc_dma_lkey = newxprt->sc_phys_mr->lkey;
+ } else
+ newxprt->sc_dma_lkey =
+ newxprt->sc_cm_id->device->local_dma_lkey;
+
/* Post receive buffers */
for (i = 0; i < newxprt->sc_max_requests; i++) {
ret = svc_rdma_post_recv(newxprt);
@@ -961,6 +1148,9 @@ static void __svc_rdma_free(struct work_struct *work)
WARN_ON(atomic_read(&rdma->sc_ctxt_used) != 0);
WARN_ON(atomic_read(&rdma->sc_dma_used) != 0);
+ /* De-allocate fastreg mr */
+ rdma_dealloc_frmr_q(rdma);
+
/* Destroy the QP if present (not a listener) */
if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
ib_destroy_qp(rdma->sc_qp);
@@ -1014,21 +1204,59 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt)
return 1;
}
+/*
+ * Attempt to register the kvec representing the RPC memory with the
+ * device.
+ *
+ * Returns:
+ * NULL : The device does not support fastreg or there were no more
+ * fastreg mr.
+ * frmr : The kvec register request was successfully posted.
+ * <0 : An error was encountered attempting to register the kvec.
+ */
+int svc_rdma_fastreg(struct svcxprt_rdma *xprt,
+ struct svc_rdma_fastreg_mr *frmr)
+{
+ struct ib_send_wr fastreg_wr;
+ u8 key;
+
+ /* Bump the key */
+ key = (u8)(frmr->mr->lkey & 0x000000FF);
+ ib_update_fast_reg_key(frmr->mr, ++key);
+
+ /* Prepare FASTREG WR */
+ memset(&fastreg_wr, 0, sizeof fastreg_wr);
+ fastreg_wr.opcode = IB_WR_FAST_REG_MR;
+ fastreg_wr.send_flags = IB_SEND_SIGNALED;
+ fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva;
+ fastreg_wr.wr.fast_reg.page_list = frmr->page_list;
+ fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len;
+ fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+ fastreg_wr.wr.fast_reg.length = frmr->map_len;
+ fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags;
+ fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey;
+ return svc_rdma_send(xprt, &fastreg_wr);
+}
+
int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
{
- struct ib_send_wr *bad_wr;
+ struct ib_send_wr *bad_wr, *n_wr;
+ int wr_count;
+ int i;
int ret;
if (test_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags))
return -ENOTCONN;
BUG_ON(wr->send_flags != IB_SEND_SIGNALED);
- BUG_ON(((struct svc_rdma_op_ctxt *)(unsigned long)wr->wr_id)->wr_op !=
- wr->opcode);
+ wr_count = 1;
+ for (n_wr = wr->next; n_wr; n_wr = n_wr->next)
+ wr_count++;
+
/* If the SQ is full, wait until an SQ entry is available */
while (1) {
spin_lock_bh(&xprt->sc_lock);
- if (xprt->sc_sq_depth == atomic_read(&xprt->sc_sq_count)) {
+ if (xprt->sc_sq_depth < atomic_read(&xprt->sc_sq_count) + wr_count) {
spin_unlock_bh(&xprt->sc_lock);
atomic_inc(&rdma_stat_sq_starve);
@@ -1043,19 +1271,26 @@ int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr)
return 0;
continue;
}
- /* Bumped used SQ WR count and post */
- svc_xprt_get(&xprt->sc_xprt);
+ /* Take a transport ref for each WR posted */
+ for (i = 0; i < wr_count; i++)
+ svc_xprt_get(&xprt->sc_xprt);
+
+ /* Bump used SQ WR count and post */
+ atomic_add(wr_count, &xprt->sc_sq_count);
ret = ib_post_send(xprt->sc_qp, wr, &bad_wr);
- if (!ret)
- atomic_inc(&xprt->sc_sq_count);
- else {
- svc_xprt_put(&xprt->sc_xprt);
+ if (ret) {
+ set_bit(XPT_CLOSE, &xprt->sc_xprt.xpt_flags);
+ atomic_sub(wr_count, &xprt->sc_sq_count);
+ for (i = 0; i < wr_count; i ++)
+ svc_xprt_put(&xprt->sc_xprt);
dprintk("svcrdma: failed to post SQ WR rc=%d, "
"sc_sq_count=%d, sc_sq_depth=%d\n",
ret, atomic_read(&xprt->sc_sq_count),
xprt->sc_sq_depth);
}
spin_unlock_bh(&xprt->sc_lock);
+ if (ret)
+ wake_up(&xprt->sc_send_wait);
break;
}
return ret;
@@ -1079,10 +1314,14 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
length = svc_rdma_xdr_encode_error(xprt, rmsgp, err, va);
/* Prepare SGE for local address */
- atomic_inc(&xprt->sc_dma_used);
sge.addr = ib_dma_map_page(xprt->sc_cm_id->device,
p, 0, PAGE_SIZE, DMA_FROM_DEVICE);
- sge.lkey = xprt->sc_phys_mr->lkey;
+ if (ib_dma_mapping_error(xprt->sc_cm_id->device, sge.addr)) {
+ put_page(p);
+ return;
+ }
+ atomic_inc(&xprt->sc_dma_used);
+ sge.lkey = xprt->sc_dma_lkey;
sge.length = length;
ctxt = svc_rdma_get_context(xprt);
@@ -1103,6 +1342,9 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
if (ret) {
dprintk("svcrdma: Error %d posting send for protocol error\n",
ret);
+ ib_dma_unmap_page(xprt->sc_cm_id->device,
+ sge.addr, PAGE_SIZE,
+ DMA_FROM_DEVICE);
svc_rdma_put_context(ctxt, 1);
}
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 4486c59c3ac..9a288d5eea6 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -3,8 +3,8 @@
*
* Client-side transport implementation for sockets.
*
- * TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
- * TCP send fixes (C) 1998 Red Hat Software <alan@redhat.com>
+ * TCP callback races fixes (C) 1998 Red Hat
+ * TCP send fixes (C) 1998 Red Hat
* TCP NFS related read + write fixes
* (C) 1999 Dave Airlie, University of Limerick, Ireland <airlied@linux.ie>
*
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 015606b54d9..c647aab8d41 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1,7 +1,7 @@
/*
* NET4: Implementation of BSD Unix domain sockets.
*
- * Authors: Alan Cox, <alan.cox@linux.org>
+ * Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/scripts/bootgraph.pl b/scripts/bootgraph.pl
new file mode 100644
index 00000000000..2243353fe55
--- /dev/null
+++ b/scripts/bootgraph.pl
@@ -0,0 +1,147 @@
+#!/usr/bin/perl
+
+# Copyright 2008, Intel Corporation
+#
+# This file is part of the Linux kernel
+#
+# This program file 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 in a file named COPYING; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor,
+# Boston, MA 02110-1301 USA
+#
+# Authors:
+# Arjan van de Ven <arjan@linux.intel.com>
+
+
+#
+# This script turns a dmesg output into a SVG graphic that shows which
+# functions take how much time. You can view SVG graphics with various
+# programs, including Inkscape, The Gimp and Firefox.
+#
+#
+# For this script to work, the kernel needs to be compiled with the
+# CONFIG_PRINTK_TIME configuration option enabled, and with
+# "initcall_debug" passed on the kernel command line.
+#
+# usage:
+# dmesg | perl scripts/bootgraph.pl > output.svg
+#
+
+my @rows;
+my %start, %end, %row;
+my $done = 0;
+my $rowcount = 0;
+my $maxtime = 0;
+my $firsttime = 100;
+my $count = 0;
+while (<>) {
+ my $line = $_;
+ if ($line =~ /([0-9\.]+)\] calling ([a-zA-Z0-9\_]+)\+/) {
+ my $func = $2;
+ if ($done == 0) {
+ $start{$func} = $1;
+ if ($1 < $firsttime) {
+ $firsttime = $1;
+ }
+ }
+ $row{$func} = 1;
+ if ($line =~ /\@ ([0-9]+)/) {
+ my $pid = $1;
+ if (!defined($rows[$pid])) {
+ $rowcount = $rowcount + 1;
+ $rows[$pid] = $rowcount;
+ }
+ $row{$func} = $rows[$pid];
+ }
+ $count = $count + 1;
+ }
+
+ if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_]+)\+.*returned/) {
+ if ($done == 0) {
+ $end{$2} = $1;
+ $maxtime = $1;
+ }
+ }
+ if ($line =~ /Write protecting the/) {
+ $done = 1;
+ }
+ if ($line =~ /Freeing unused kernel memory/) {
+ $done = 1;
+ }
+}
+
+if ($count == 0) {
+ print "No data found in the dmesg. Make sure that 'printk.time=1' and\n";
+ print "'initcall_debug' are passed on the kernel command line.\n\n";
+ print "Usage: \n";
+ print " dmesg | perl scripts/bootgraph.pl > output.svg\n\n";
+ exit;
+}
+
+print "<?xml version=\"1.0\" standalone=\"no\"?> \n";
+print "<svg width=\"1000\" height=\"100%\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n";
+
+my @styles;
+
+$styles[0] = "fill:rgb(0,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[1] = "fill:rgb(0,255,0);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[2] = "fill:rgb(255,0,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[3] = "fill:rgb(255,255,20);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[4] = "fill:rgb(255,0,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[5] = "fill:rgb(0,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[6] = "fill:rgb(0,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[7] = "fill:rgb(0,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[8] = "fill:rgb(255,0,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[9] = "fill:rgb(255,255,128);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[10] = "fill:rgb(255,128,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+$styles[11] = "fill:rgb(128,255,255);fill-opacity:0.5;stroke-width:1;stroke:rgb(0,0,0)";
+
+my $mult = 950.0 / ($maxtime - $firsttime);
+my $threshold = ($maxtime - $firsttime) / 60.0;
+my $stylecounter = 0;
+while (($key,$value) = each %start) {
+ my $duration = $end{$key} - $start{$key};
+
+ if ($duration >= $threshold) {
+ my $s, $s2, $e, $y;
+ $s = ($value - $firsttime) * $mult;
+ $s2 = $s + 6;
+ $e = ($end{$key} - $firsttime) * $mult;
+ $w = $e - $s;
+
+ $y = $row{$key} * 150;
+ $y2 = $y + 4;
+
+ $style = $styles[$stylecounter];
+ $stylecounter = $stylecounter + 1;
+ if ($stylecounter > 11) {
+ $stylecounter = 0;
+ };
+
+ print "<rect x=\"$s\" width=\"$w\" y=\"$y\" height=\"145\" style=\"$style\"/>\n";
+ print "<text transform=\"translate($s2,$y2) rotate(90)\">$key</text>\n";
+ }
+}
+
+
+# print the time line on top
+my $time = $firsttime;
+my $step = ($maxtime - $firsttime) / 15;
+while ($time < $maxtime) {
+ my $s2 = ($time - $firsttime) * $mult;
+ my $tm = int($time * 100) / 100.0;
+ print "<text transform=\"translate($s2,89) rotate(90)\">$tm</text>\n";
+ $time = $time + $step;
+}
+
+print "</svg>\n";
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index bc677939822..e30bac141b2 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -9,7 +9,7 @@ use strict;
my $P = $0;
$P =~ s@.*/@@g;
-my $V = '0.21';
+my $V = '0.24';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -66,6 +66,7 @@ if ($#ARGV < 0) {
my $dbg_values = 0;
my $dbg_possible = 0;
my $dbg_type = 0;
+my $dbg_attr = 0;
for my $key (keys %debug) {
eval "\${dbg_$key} = '$debug{$key}';"
}
@@ -112,7 +113,10 @@ our $Attribute = qr{
const|
__read_mostly|
__kprobes|
- __(?:mem|cpu|dev|)(?:initdata|init)
+ __(?:mem|cpu|dev|)(?:initdata|init)|
+ ____cacheline_aligned|
+ ____cacheline_aligned_in_smp|
+ ____cacheline_internodealigned_in_smp
}x;
our $Modifier;
our $Inline = qr{inline|__always_inline|noinline};
@@ -142,6 +146,11 @@ our $UTF8 = qr {
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
}x;
+our $typeTypedefs = qr{(?x:
+ (?:__)?(?:u|s|be|le)(?:\d|\d\d)|
+ atomic_t
+)};
+
our @typeList = (
qr{void},
qr{(?:unsigned\s+)?char},
@@ -155,7 +164,6 @@ our @typeList = (
qr{float},
qr{double},
qr{bool},
- qr{(?:__)?(?:u|s|be|le)(?:8|16|32|64)},
qr{struct\s+$Ident},
qr{union\s+$Ident},
qr{enum\s+$Ident},
@@ -175,6 +183,7 @@ sub build_types {
(?:$Modifier\s+|const\s+)*
(?:
(?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)|
+ (?:$typeTypedefs\b)|
(?:${all}\b)
)
(?:\s+$Modifier|\s+const)*
@@ -331,7 +340,7 @@ sub sanitise_line {
$off++;
next;
}
- if (substr($line, $off, 2) eq '*/') {
+ if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
$sanitise_quote = '';
substr($res, $off, 2, "$;$;");
$off++;
@@ -404,6 +413,7 @@ sub ctx_statement_block {
# context.
if ($off >= $len) {
for (; $remain > 0; $line++) {
+ last if (!defined $lines[$line]);
next if ($lines[$line] =~ /^-/);
$remain--;
$loff = $len;
@@ -669,6 +679,22 @@ sub ctx_has_comment {
return ($cmt ne '');
}
+sub raw_line {
+ my ($linenr, $cnt) = @_;
+
+ my $offset = $linenr - 1;
+ $cnt++;
+
+ my $line;
+ while ($cnt) {
+ $line = $rawlines[$offset++];
+ next if (defined($line) && $line =~ /^-/);
+ $cnt--;
+ }
+
+ return $line;
+}
+
sub cat_vet {
my ($vet) = @_;
my ($res, $coded);
@@ -782,9 +808,9 @@ sub annotate_values {
}
$type = 'N';
- } elsif ($cur =~ /^(if|while|typeof|__typeof__|for)\b/o) {
+ } elsif ($cur =~ /^(if|while|for)\b/o) {
print "COND($1)\n" if ($dbg_values > 1);
- $av_pending = 'N';
+ $av_pending = 'E';
$type = 'N';
} elsif ($cur =~/^(case)/o) {
@@ -792,7 +818,7 @@ sub annotate_values {
$av_pend_colon = 'C';
$type = 'N';
- } elsif ($cur =~/^(return|else|goto)/o) {
+ } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
print "KEYWORD($1)\n" if ($dbg_values > 1);
$type = 'N';
@@ -858,7 +884,7 @@ sub annotate_values {
print "CLOSE($1)\n" if ($dbg_values > 1);
$type = 'N';
- } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&(?!\&))/o) {
+ } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
my $variant;
print "OPV($1)\n" if ($dbg_values > 1);
@@ -892,12 +918,22 @@ sub annotate_values {
sub possible {
my ($possible, $line) = @_;
- print "CHECK<$possible> ($line)\n" if ($dbg_possible > 1);
- if ($possible !~ /^(?:$Modifier|$Storage|$Type|DEFINE_\S+)$/ &&
- $possible ne 'goto' && $possible ne 'return' &&
- $possible ne 'case' && $possible ne 'else' &&
- $possible ne 'asm' && $possible ne '__asm__' &&
- $possible !~ /^(typedef|struct|enum)\b/) {
+ print "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+ if ($possible !~ /(?:
+ ^(?:
+ $Modifier|
+ $Storage|
+ $Type|
+ DEFINE_\S+|
+ goto|
+ return|
+ case|
+ else|
+ asm|__asm__|
+ do
+ )$|
+ ^(?:typedef|struct|enum)\b
+ )/x) {
# Check for modifiers.
$possible =~ s/\s*$Storage\s*//g;
$possible =~ s/\s*$Sparse\s*//g;
@@ -915,6 +951,8 @@ sub possible {
push(@typeList, $possible);
}
build_types();
+ } else {
+ warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
}
}
@@ -954,6 +992,33 @@ sub CHK {
}
}
+sub check_absolute_file {
+ my ($absolute, $herecurr) = @_;
+ my $file = $absolute;
+
+ ##print "absolute<$absolute>\n";
+
+ # See if any suffix of this path is a path within the tree.
+ while ($file =~ s@^[^/]*/@@) {
+ if (-f "$root/$file") {
+ ##print "file<$file>\n";
+ last;
+ }
+ }
+ if (! -f _) {
+ return 0;
+ }
+
+ # It is, so see if the prefix is acceptable.
+ my $prefix = $absolute;
+ substr($prefix, -length($file)) = '';
+
+ ##print "prefix<$prefix>\n";
+ if ($prefix ne ".../") {
+ WARN("use relative pathname instead of absolute in changelog text\n" . $herecurr);
+ }
+}
+
sub process {
my $filename = shift;
@@ -991,6 +1056,7 @@ sub process {
# suppression flags
my %suppress_ifbraces;
+ my %suppress_whiletrailers;
# Pre-scan the patch sanitizing the lines.
# Pre-scan the patch looking for any __setup documentation.
@@ -1025,9 +1091,14 @@ sub process {
# edge is a close comment then we must be in a comment
# at context start.
my $edge;
- for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) {
- next if ($line =~ /^-/);
- ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
+ my $cnt = $realcnt;
+ for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+ next if (defined $rawlines[$ln - 1] &&
+ $rawlines[$ln - 1] =~ /^-/);
+ $cnt--;
+ #print "RAW<$rawlines[$ln - 1]>\n";
+ ($edge) = (defined $rawlines[$ln - 1] &&
+ $rawlines[$ln - 1] =~ m@(/\*|\*/)@);
last if (defined $edge);
}
if (defined $edge && $edge eq '*/') {
@@ -1075,6 +1146,7 @@ sub process {
$linenr++;
my $rawline = $rawlines[$linenr - 1];
+ my $hunk_line = ($realcnt != 0);
#extract the line range in the file after the patch is applied
if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
@@ -1090,6 +1162,7 @@ sub process {
$prev_values = 'E';
%suppress_ifbraces = ();
+ %suppress_whiletrailers = ();
next;
# track the line number as we move through the hunk, note that
@@ -1125,7 +1198,7 @@ sub process {
$realfile = $1;
$realfile =~ s@^[^/]*/@@;
- if ($realfile =~ m@include/asm/@) {
+ if ($realfile =~ m@^include/asm/@) {
ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
}
next;
@@ -1159,6 +1232,20 @@ sub process {
$herecurr) if (!$emitted_corrupt++);
}
+# Check for absolute kernel paths.
+ if ($tree) {
+ while ($line =~ m{(?:^|\s)(/\S*)}g) {
+ my $file = $1;
+
+ if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+ check_absolute_file($1, $herecurr)) {
+ #
+ } else {
+ check_absolute_file($file, $herecurr);
+ }
+ }
+ }
+
# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
if (($realfile =~ /^$/ || $line =~ /^\+/) &&
$rawline !~ m/^$UTF8*$/) {
@@ -1171,11 +1258,8 @@ sub process {
ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
}
-#ignore lines being removed
- if ($line=~/^-/) {next;}
-
-# check we are in a valid source file if not then ignore this hunk
- next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+# ignore non-hunk lines and lines being removed
+ next if (!$hunk_line || $line =~ /^-/);
#trailing whitespace
if ($line =~ /^\+.*\015/) {
@@ -1186,6 +1270,10 @@ sub process {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
ERROR("trailing whitespace\n" . $herevet);
}
+
+# check we are in a valid source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
#80 column limit
if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
$rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
@@ -1200,8 +1288,8 @@ sub process {
WARN("adding a line without newline at end of file\n" . $herecurr);
}
-# check we are in a valid source file *.[hc] if not then ignore this hunk
- next if ($realfile !~ /\.[hc]$/);
+# check we are in a valid source file C or perl if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|pl)$/);
# at the beginning of a line any tabs must come first and anything
# more than 8 must use tabs.
@@ -1211,15 +1299,18 @@ sub process {
ERROR("code indent should use tabs where possible\n" . $herevet);
}
+# check we are in a valid C source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c)$/);
+
# check for RCS/CVS revision markers
if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
}
# Check for potential 'bare' types
- my ($stat, $cond, $line_nr_next, $remain_next);
+ my ($stat, $cond, $line_nr_next, $remain_next, $off_next);
if ($realcnt && $line =~ /.\s*\S/) {
- ($stat, $cond, $line_nr_next, $remain_next) =
+ ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
ctx_statement_block($linenr, $realcnt, 0);
$stat =~ s/\n./\n /g;
$cond =~ s/\n./\n /g;
@@ -1240,7 +1331,7 @@ sub process {
possible($type, "A:" . $s);
# definitions in global scope can only start with types
- } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) {
+ } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
possible($1, "B:" . $s);
}
@@ -1294,10 +1385,6 @@ sub process {
ERROR("switch and case should be at the same indent\n$hereline$err");
}
}
- if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
- $line !~ /\G(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$/g) {
- ERROR("trailing statements should be on next line\n" . $herecurr);
- }
# if/while/etc brace do not go on next line, unless defining a do while loop,
# or if that brace on the next line is for something else
@@ -1338,6 +1425,91 @@ sub process {
}
}
+# Check relative indent for conditionals and blocks.
+ if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+ my ($s, $c) = ($stat, $cond);
+
+ substr($s, 0, length($c), '');
+
+ # Make sure we remove the line prefixes as we have
+ # none on the first line, and are going to readd them
+ # where necessary.
+ $s =~ s/\n./\n/gs;
+
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
+
+ # We want to check the first line inside the block
+ # starting at the end of the conditional, so remove:
+ # 1) any blank line termination
+ # 2) any opening brace { on end of the line
+ # 3) any do (...) {
+ my $continuation = 0;
+ my $check = 0;
+ $s =~ s/^.*\bdo\b//;
+ $s =~ s/^\s*{//;
+ if ($s =~ s/^\s*\\//) {
+ $continuation = 1;
+ }
+ if ($s =~ s/^\s*?\n//) {
+ $check = 1;
+ $cond_lines++;
+ }
+
+ # Also ignore a loop construct at the end of a
+ # preprocessor statement.
+ if (($prevline =~ /^.\s*#\s*define\s/ ||
+ $prevline =~ /\\\s*$/) && $continuation == 0) {
+ $check = 0;
+ }
+
+ my $cond_ptr = -1;
+ $continuation = 0;
+ while ($cond_ptr != $cond_lines) {
+ $cond_ptr = $cond_lines;
+
+ # If we see an #else/#elif then the code
+ # is not linear.
+ if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+ $check = 0;
+ }
+
+ # Ignore:
+ # 1) blank lines, they should be at 0,
+ # 2) preprocessor lines, and
+ # 3) labels.
+ if ($continuation ||
+ $s =~ /^\s*?\n/ ||
+ $s =~ /^\s*#\s*?/ ||
+ $s =~ /^\s*$Ident\s*:/) {
+ $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+ $s =~ s/^.*?\n//;
+ $cond_lines++;
+ }
+ }
+
+ my (undef, $sindent) = line_stats("+" . $s);
+ my $stat_real = raw_line($linenr, $cond_lines);
+
+ # Check if either of these lines are modified, else
+ # this is not this patch's fault.
+ if (!defined($stat_real) ||
+ $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+ $check = 0;
+ }
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
+
+ #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+ if ($check && (($sindent % 8) != 0 ||
+ ($sindent <= $indent && $s ne ''))) {
+ WARN("suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+ }
+ }
+
# Track the 'values' across context and added lines.
my $opline = $line; $opline =~ s/^./ /;
my ($curr_values, $curr_vars) =
@@ -1363,6 +1535,15 @@ sub process {
}
next;
}
+# TEST: allow direct testing of the attribute matcher.
+ if ($dbg_attr) {
+ if ($line =~ /^.\s*$Attribute\s*$/) {
+ ERROR("TEST: is attr\n" . $herecurr);
+ } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) {
+ ERROR("TEST: is not attr ($1 is)\n". $herecurr);
+ }
+ next;
+ }
# check for initialisation to aggregates open brace on the next line
if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ &&
@@ -1395,13 +1576,14 @@ sub process {
if (($line =~ /EXPORT_SYMBOL.*\((.*)\)/) ||
($line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
my $name = $1;
- if (($prevline !~ /^}/) &&
- ($prevline !~ /^\+}/) &&
- ($prevline !~ /^ }/) &&
- ($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) &&
- ($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) &&
- ($prevline !~ /^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(/) &&
- ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) {
+ if ($prevline !~ /(?:
+ ^.}|
+ ^.DEFINE_$Ident\(\Q$name\E\)|
+ ^.DECLARE_$Ident\(\Q$name\E\)|
+ ^.LIST_HEAD\(\Q$name\E\)|
+ ^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+ \b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)
+ )/x) {
WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
}
}
@@ -1422,6 +1604,7 @@ sub process {
if ($line =~ /\btypedef\s/ &&
$line !~ /\btypedef\s+$Type\s+\(\s*\*?$Ident\s*\)\s*\(/ &&
$line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+ $line !~ /\b$typeTypedefs\b/ &&
$line !~ /\b__bitwise(?:__|)\b/) {
WARN("do not add new typedefs\n" . $herecurr);
}
@@ -1493,11 +1676,13 @@ sub process {
# check for spacing round square brackets; allowed:
# 1. with a type on the left -- int [] a;
-# 2. at the beginning of a line for slice initialisers -- [0..10] = 5,
+# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+# 3. inside a curly brace -- = { [0...10] = 5 }
while ($line =~ /(.*?\s)\[/g) {
my ($where, $prefix) = ($-[1], $1);
if ($prefix !~ /$Type\s+$/ &&
- ($where != 0 || $prefix !~ /^.\s+$/)) {
+ ($where != 0 || $prefix !~ /^.\s+$/) &&
+ $prefix !~ /{\s+$/) {
ERROR("space prohibited before open square bracket '['\n" . $herecurr);
}
}
@@ -1632,7 +1817,7 @@ sub process {
# unary operator, or a cast
} elsif ($op eq '!' || $op eq '~' ||
$opv eq '*U' || $opv eq '-U' ||
- $opv eq '&U') {
+ $opv eq '&U' || $opv eq '&&U') {
if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
ERROR("space required before that '$op' $at\n" . $hereptr);
}
@@ -1785,7 +1970,26 @@ sub process {
# Check for illegal assignment in if conditional -- and check for trailing
# statements after the conditional.
- if ($line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+ if ($line =~ /do\s*(?!{)/) {
+ my ($stat_next) = ctx_statement_block($line_nr_next,
+ $remain_next, $off_next);
+ $stat_next =~ s/\n./\n /g;
+ ##print "stat<$stat> stat_next<$stat_next>\n";
+
+ if ($stat_next =~ /^\s*while\b/) {
+ # If the statement carries leading newlines,
+ # then count those as offsets.
+ my ($whitespace) =
+ ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset =
+ statement_rawlines($whitespace) - 1;
+
+ $suppress_whiletrailers{$line_nr_next +
+ $offset} = 1;
+ }
+ }
+ if (!defined $suppress_whiletrailers{$linenr} &&
+ $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
my ($s, $c) = ($stat, $cond);
if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/) {
@@ -1800,57 +2004,16 @@ sub process {
if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
$c !~ /}\s*while\s*/)
{
- ERROR("trailing statements should be on next line\n" . $herecurr);
- }
- }
-
-# Check relative indent for conditionals and blocks.
- if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
- my ($s, $c) = ($stat, $cond);
-
- substr($s, 0, length($c), '');
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
- # Make sure we remove the line prefixes as we have
- # none on the first line, and are going to readd them
- # where necessary.
- $s =~ s/\n./\n/gs;
-
- # We want to check the first line inside the block
- # starting at the end of the conditional, so remove:
- # 1) any blank line termination
- # 2) any opening brace { on end of the line
- # 3) any do (...) {
- my $continuation = 0;
- my $check = 0;
- $s =~ s/^.*\bdo\b//;
- $s =~ s/^\s*{//;
- if ($s =~ s/^\s*\\//) {
- $continuation = 1;
- }
- if ($s =~ s/^\s*\n//) {
- $check = 1;
- }
-
- # Also ignore a loop construct at the end of a
- # preprocessor statement.
- if (($prevline =~ /^.\s*#\s*define\s/ ||
- $prevline =~ /\\\s*$/) && $continuation == 0) {
- $check = 0;
- }
-
- # Ignore the current line if its is a preprocessor
- # line.
- if ($s =~ /^\s*#\s*/) {
- $check = 0;
- }
-
- my (undef, $sindent) = line_stats("+" . $s);
-
- ##print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s>\n";
+ my $stat_real = raw_line($linenr, $cond_lines);
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
- if ($check && (($sindent % 8) != 0 ||
- ($sindent <= $indent && $s ne ''))) {
- WARN("suspect code indent for conditional statements\n" . $herecurr);
+ ERROR("trailing statements should be on next line\n" . $herecurr . $stat_real);
}
}
@@ -1877,6 +2040,15 @@ sub process {
ERROR("trailing statements should be on next line\n" . $herecurr);
}
}
+# case and default should not have general statements after them
+ if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+ $line !~ /\G(?:
+ (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+ \s*return\s+
+ )/xg)
+ {
+ ERROR("trailing statements should be on next line\n" . $herecurr);
+ }
# Check for }<nl>else {, these must be at the same
# indent level to be relevant to each other.
@@ -1913,12 +2085,17 @@ sub process {
#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
- my $checkfile = "include/linux/$1.h";
- if (-f "$root/$checkfile" && $realfile ne $checkfile &&
+ my $file = "$1.h";
+ my $checkfile = "include/linux/$file";
+ if (-f "$root/$checkfile" &&
+ $realfile ne $checkfile &&
$1 ne 'irq')
{
- WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
- $herecurr);
+ if ($realfile =~ m{^arch/}) {
+ CHK("Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ } else {
+ WARN("Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ }
}
}
@@ -1953,8 +2130,8 @@ sub process {
# Extract the remainder of the define (if any) and
# rip off surrounding spaces, and trailing \'s.
$rest = '';
- while ($off != 0 || ($cnt > 0 && $rest =~ /(?:^|\\)\s*$/)) {
- #print "ADDING $off <" . substr($lines[$ln - 1], $off) . ">\n";
+ while ($off != 0 || ($cnt > 0 && $rest =~ /\\\s*$/)) {
+ #print "ADDING cnt<$cnt> $off <" . substr($lines[$ln - 1], $off) . "> rest<$rest>\n";
if ($off != 0 || $lines[$ln - 1] !~ /^-/) {
$rest .= substr($lines[$ln - 1], $off) . "\n";
$cnt--;
@@ -1978,9 +2155,10 @@ sub process {
$dstat =~ s/\s*$//s;
# Flatten any parentheses and braces
- while ($dstat =~ s/\([^\(\)]*\)/1/) {
- }
- while ($dstat =~ s/\{[^\{\}]*\}/1/) {
+ while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+ $dstat =~ s/\{[^\{\}]*\}/1/ ||
+ $dstat =~ s/\[[^\{\}]*\]/1/)
+ {
}
my $exceptions = qr{
@@ -2003,6 +2181,7 @@ sub process {
if ($dstat ne '' &&
$dstat !~ /^(?:$Ident|-?$Constant)$/ &&
$dstat !~ /$exceptions/ &&
+ $dstat !~ /^\.$Ident\s*=/ &&
$dstat =~ /$Operators/)
{
ERROR("Macros with complex values should be enclosed in parenthesis\n" . "$here\n$ctx\n");
@@ -2103,10 +2282,10 @@ sub process {
}
if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
my $herectx = $here . "\n";;
- my $end = $linenr + statement_rawlines($block) - 1;
+ my $cnt = statement_rawlines($block);
- for (my $ln = $linenr - 1; $ln < $end; $ln++) {
- $herectx .= $rawlines[$ln] . "\n";;
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";;
}
WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
@@ -2281,6 +2460,7 @@ sub process {
my $string;
while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
$string = substr($rawline, $-[1], $+[1] - $-[1]);
+ $string =~ s/%%/__/g;
if ($string =~ /(?<!%)%L[udi]/) {
WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
last;
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 473f94e56ea..d4dc222a74f 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -206,6 +206,20 @@ static void do_usb_table(void *symval, unsigned long size,
do_usb_entry_multi(symval + i, mod);
}
+/* Looks like: hid:bNvNpN */
+static int do_hid_entry(const char *filename,
+ struct hid_device_id *id, char *alias)
+{
+ id->vendor = TO_NATIVE(id->vendor);
+ id->product = TO_NATIVE(id->product);
+
+ sprintf(alias, "hid:b%04X", id->bus);
+ ADD(alias, "v", id->vendor != HID_ANY_ID, id->vendor);
+ ADD(alias, "p", id->product != HID_ANY_ID, id->product);
+
+ return 1;
+}
+
/* Looks like: ieee1394:venNmoNspNverN */
static int do_ieee1394_entry(const char *filename,
struct ieee1394_device_id *id, char *alias)
@@ -745,6 +759,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
else if (sym_is(symname, "__mod_usb_device_table"))
/* special case to handle bcdDevice ranges */
do_usb_table(symval, sym->st_size, mod);
+ else if (sym_is(symname, "__mod_hid_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct hid_device_id), "hid",
+ do_hid_entry, mod);
else if (sym_is(symname, "__mod_ieee1394_device_table"))
do_table(symval, sym->st_size,
sizeof(struct ieee1394_device_id), "ieee1394",
diff --git a/sound/aoa/soundbus/soundbus.h b/sound/aoa/soundbus/soundbus.h
index 622cd37a011..a0f223c13f6 100644
--- a/sound/aoa/soundbus/soundbus.h
+++ b/sound/aoa/soundbus/soundbus.h
@@ -8,7 +8,7 @@
#ifndef __SOUNDBUS_H
#define __SOUNDBUS_H
-#include <asm/of_device.h>
+#include <linux/of_device.h>
#include <sound/pcm.h>
#include <linux/list.h>